Object Oriented Programming with Java

Revision 0.3

Lee Chuk Munn July 19, 1999

Contents
1 Introducing Java 1.1 What is Java? . . . . . . . . . 1.1.1 Simple . . . . . . . . . 1.1.2 Object Oriented . . . 1.1.3 Network Savvy . . . . 1.1.4 Interpreted . . . . . . 1.1.5 Robust . . . . . . . . 1.1.6 Secure . . . . . . . . . 1.1.7 Architecture Neutral . 1.1.8 Portable . . . . . . . . 1.1.9 High Performance . . 1.1.10 Multithreaded . . . . 1.1.11 Dynamic Language . . 1.2 First Java Program . . . . . . 1.2.1 Java Development Kit 1.2.2 Java CLASSPATH . . . 2 The 2.1 2.2 2.3 2.4 1 1 1 2 2 2 2 2 4 4 4 5 5 5 6 7 8 8 8 9 10 10 10 10 11 11 11 11 12 12 13 13

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

2.5

Java Programming Language Reserved Word . . . . . . . . . . . . . . . . Primitive Types . . . . . . . . . . . . . . . . Identifiers . . . . . . . . . . . . . . . . . . . Operators . . . . . . . . . . . . . . . . . . . 2.4.1 Binary Operators . . . . . . . . . . . 2.4.2 String Concatenation . . . . . . . . 2.4.3 Unary Operator . . . . . . . . . . . 2.4.4 Increment and Decrement Operators 2.4.5 Conditional Operators . . . . . . . . 2.4.6 Relational Operators . . . . . . . . . 2.4.7 Bitwise Operators . . . . . . . . . . 2.4.8 Conditional Expression Operator . . 2.4.9 Assignment Operators . . . . . . . . Flow Control Statements . . . . . . . . . . . 2.5.1 Comments . . . . . . . . . . . . . . . i

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

. . . . . . . . . . . . . . .

CONTENTS

2.6 2.7

2.5.2 Semicolons, Blocks and Whitespace . 2.5.3 if-else Statement . . . . . . . . . . . 2.5.4 switch-case Statement . . . . . . . . 2.5.5 while Statement . . . . . . . . . . . . 2.5.6 do-while Statement . . . . . . . . . . 2.5.7 for Statement . . . . . . . . . . . . . 2.5.8 break, continue and Label Statement 2.5.9 return Statement . . . . . . . . . . . Array . . . . . . . . . . . . . . . . . . . . . . 2.6.1 Multidimensional Array . . . . . . . . Defining Methods . . . . . . . . . . . . . . . . 2.7.1 main Method . . . . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

. . . . . . . . . . . .

14 14 15 17 17 17 18 19 19 20 21 22 23 23 23 23 24 24 24 25 25 26 26 26 27 29 30 31 34 35 36 37 38 39 42 42 42 44 45 45 47

3 Object Orientation 3.1 Why the Hype? . . . . . . . . . . . . . 3.2 Object Concepts . . . . . . . . . . . . 3.2.1 What is an Object? . . . . . . 3.2.2 What is a Class? . . . . . . . . 3.2.3 What is a Property? . . . . . . 3.2.4 What is Encapsulation? . . . . 3.2.5 What is Abstraction? . . . . . 3.2.6 What is Inheritance? . . . . . . 3.2.7 What is Polymorphism? . . . . 3.3 Expressing Objects with Java . . . . . 3.3.1 Objects and Class . . . . . . . 3.3.2 Constructors and Destructors . 3.3.3 Encapsulation . . . . . . . . . . 3.3.4 Method and Member Visibility 3.3.5 Inheritance . . . . . . . . . . . 3.3.6 Polymorphism . . . . . . . . . 3.3.7 Overriding . . . . . . . . . . . 3.3.8 Overloading . . . . . . . . . . . 3.3.9 super and this . . . . . . . . 3.4 final Keyword . . . . . . . . . . . . . 3.5 static Keyword . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . .

4 Abstract Class and Interface 4.1 Abstract Class . . . . . . . . . . . . . . . . . . . 4.1.1 Defining an Abstract Class . . . . . . . . 4.2 Interface . . . . . . . . . . . . . . . . . . . . . . . 4.2.1 Defining an Interface . . . . . . . . . . . . 4.2.2 Implementing an Interface . . . . . . . . . 4.3 Differences between Abstract Class and Interface

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

. . . . . .

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

ii

. . . . All rights reserved. . . . . . .7 TextField . . . . . . . . . .2 GridLayout . . . 5. . 49 49 51 52 53 53 55 55 56 57 57 58 58 59 59 60 61 61 62 62 62 63 63 64 65 66 66 67 67 68 69 69 71 72 73 74 75 76 76 77 77 77 iii .1. .5 List . . . . . . . . . . . . . . . . .1 paint(Graphics) Method . . . . . . . . . . . .3. . . . . . . Members . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4 AWT Components . . . .1 Instance Initializers . . . . . . . . . .4 Choice . . . . . . . . . . . .1 The MVC Architecture 7. . . . . . . . . . . . . . . . . . . . . . .1 The Model . . . . . . . . . . . . . . .6 Label . . . . . . 5. . . . . .1 MenuBar . .6. . .1 FlowLayout .2 LayoutManager . . .3 CheckboxGroup . . . . . . . .1. . . . . . . . . . . . . . . . . . . .3. . . 5. . .8. . . . . . . . . . . . . . . . . . . . . . . . 6. . . . . . .4. 5. . . .2. . . . . . . . . .4. . . . . . .2 Checkbox . . . . . . .3 The Controller . . . . . . . . .2 repaint() Method . . . . . . . . . . . .3 Container . . . . . .4. . . . . . . . 5. . . . .1. . . . . .1 Referencing Containing Class’ 6. . . . . . . . . . . . 7. . . . . . . . . . . . . . . . . . . . . . .2. . . . . 5. . . . . . . . . . . . . . . . . . . . . . . . 5. . . . . .7 Customizing Components . . . . . . . . . . . . . . . . . . . . . .4. . . . . . .9 AWT Events . . .8 TextArea . . . . . .1 Using Font . .2 Frame . . . . 5. Copyright c July 1999 Lee Chuk Munn. . . . . . . . . . . . . . . . . . 5. .4. . . . . . .1 Member Class . . . . . . . . . . . . . . . . . . . . . . . . . . 5. . . . . . . . . .8 Adding Menus to Frame . . . . . . . . . . . . . . . . . . . .1 Button . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5. . . . . . . .2 Anonymous Class . . .1. . . . . . . . . 5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 Handling AWT Events 7. . . . . . . . . . . . . . . . . 5. . . . . . . . . . . . . . . . . . . . . . .5. . . . . 5. . .3 BorderLayout . . . . . . . . . 5. . . . . . . . . . . . . 5. .1 Component and Container . . . . . . . . . . . .5. . . . . . . . 5. . . . . . . . . . . . . . 6. . .4. . . . . . . . .4. . . . 7. . . . . . . . . .8. . . .3 update(Graphics) Method . . . . . .8. .6 Graphics . . . . . 5. . .2 The View . . . . . . .2. . . .2 Menu . . . . . . . . . 5. . . . .2. . . . . . .CONTENTS 5 Building GUIs with AWT 5. . . . .1 Using Panel in Complex GUIs . . . . . . . . . . .1. . 5. . . 6 Inner Class 6. . . . . . . . 5. . .3 MenuItem and CheckboxMenuItem 5. . . . . . . . .2 Instantiating Member Classes 6. . . . . . . . . . . . . . . . . . . . . . . . . . 5. 7. . . 5. . . . . . . 5. . . .2 Events . . . . . . . . . . . . . . . . . . . . . . . . . .4. . . . . . 5. . . 5. . . . . . . . 5. . . . . . . . . . . . . 5. . . . . . . . . . . . . . . . .5 The AWT Paint Cycle . . . . . . .

. . . . . . . .3 Validating a Deserialized Object . .1. .1.2. . . . . . . . . . . . . .2. . . . 7. . . . . . . . . . . . . . 8. . . . . . . . . . . . . .5 Declaring Exceptions . . . . . . . .1 Specifying What Gets Serialized . . . . .2. . . . . . .1 The AWT Event Model . . .. . . . . . . . . . . .4 Event Source .2. . . . . . . 77 77 79 80 80 80 82 83 84 84 84 85 89 89 89 90 91 92 94 94 95 98 98 100 100 101 103 105 107 107 112 112 113 113 114 114 115 116 118 8 Exceptions 8. . . . . . . . . . . . . . . . . . 7. . .1 Serialization . . . . . . . . .1 The Serializable Interface . . .CONTENTS 7. . . . . . . . . . . . . . .3. . . . . . . . . . . .3 AccountListener Interface . . .3 A File Copy Example . . .2. . . . . . . . .2 The AccountEvent Object . . . . . . . . . . . . . . . 7. . . .2 Performing I/O with Account . . 8. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7. . . . . . .2 Exception Objects . Copyright c July 1999 Lee Chuk Munn.2 Creating Your Own Exception . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 Object Serialization 10.2 Customizing the Serialization Process . . . . . .1 InputStream . . . . . . . . . . 9. . 10. .3 7. . . . . . . . . . . . . . . . . . . . . . . . 7. . . . . . .3 Stream Chaining . .3.1. 8. . . . . . .6 Generating Exceptions .1. . . . . . . . . . . . . 10.2. . . . . . .2 readObject and writeObject Method . . . . . . . iv . . . . . .1. .. . . . . All rights reserved. . . . . . .1. . . . . . .1 Decorator Design . . . . .3. . . . . . . 10. . . .1. . . . . . . . . Listener and Event Objects 7. . . Creating Customized Events . . . . .6 A Button Example . . . . . . . 7. . . 9. . . . . . . . . . . . . 9. . . . . . . . 10. . . . . . . .1 Exceptions . . 10. . . . . . . . . . . . . . . .3. . .4 And finally. . . . . . . . . . . .4 Versioning . . . . 7. . . . . . . . . . . . . . . . . . . . .3. . . .2. . . 9.2 Identifying Source. . . . . . . . . . . .1 The File Class . .2. . . . . . 9. . . . 9.2 ObjectInputStream and ObjectOutputStream 10. .3 try-catch Block . . . . . . . . . 8. . . . 9 Streams 9. . . . . . . . . . . . .2. . . . . 8. . . .7 Another Button Example . . . 7. . 9.2. . . . .1 An Exceptional Example 8. . . . . . . . .2 Character and Byte Streams . . . . . .3 Event Listener Interface . . . . . . . . . . . . 7. . . . . . . . . . . . . . . 10. . . . .3. . . . . . . . . . . . . . . .2. . . .5 Event Objects . . . .1 Account Class Again . . . . . . . . .1. .2. . . .4 Event Listener Registration/Deregistration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.2 OutputStream .

. . . . . . . . . . .2. . .1 Addresses and Ports . . . .2.2 Enhancing AccountServer . . . . . . . . . . 129 . . . . . . . . . .4 TightRate. . . .3. .1. . . . . . . . . . .1. . . . 120 . . . . . . . . . . . A.6 AccountServerAPI. . . 12. . 12. . . . . . . . . . . . .3.2 ConnectionHandler. . . . . . . .3 Writing the Server API . . . . . . . . . . . . .1. . . All rights reserved. . . . . .3 AccountProtocol. . . . . . . . . . . . . . .2. . . . . . .1 synchronized Keyword . . . 12. 123 . .1 Defining the Protocol . .3 AccountEvent. . . .3 Account Server . .java . . . 121 . A. . . . 12. .5 ErroneousAmountException. . .1 Creating a Thread . 12. A. . . . . . .4 Counter. . . . . . .java . . 125 . . . . A. . . .2 Client-Server Model . . . . . . . . . . . . . . . . . . 133 135 136 137 139 143 143 143 150 151 154 158 160 163 163 163 166 166 166 167 167 167 168 168 168 169 169 169 169 170 172 172 173 173 . . . . . . . . . . . . . . . . . . . . .4 Using the AccountServerAPI 12 Threads and Synchronization 12. . .java . . 12. . .3.2 SavingAccount. . . . . . . . .5 Interest. . . . . . . . . . . . . . . . . . . . . . . . .CONTENTS 11 Networking 11. . . . . .1 FixedDepositAccount. .5 Implication of static on Threads . . . . . . . . .java . . . . . . . . . . . . . . . . . . A. . 11. . . . . . . .3 Synchrnonization . . . .4 States of a Thread . . . . .2 Thread Safe Objects .4 AccountException. . . . . . . . . . . . . . . . . 12. . .2 Subclass and Implementations . . . . . . . . . . . . . .3. . .java . . .1. . . .1 AccountServer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A. . . . . . . . . . . . . . . .java .1. . . . . . . . . . . . . . A. . . . . . . . . .java . . . . . . . . . . . . . . 11. . . . . . . .java . . . . . . . .1. . . . . .1 Core Classes . Copyright c July 1999 Lee Chuk Munn. A. . . . . . . . . . . . . . . . . .2 AccountListener. .3 GenerousRate. . .1 Account. . .java . . A. . . . . . A. . . . . . . . . . .2. . . . . . .5 Counter. . . . . . . . 11. . .2. . . . . . . . . . . . . .2 Thread Class . . . .2 Writing a Server . .1. . . . . . . . . . . . . . .java . . . . 11. . A. . . . . . . v . . . . . . . . . . . . . .java . . . . .java .2. . . . . . . . . . .java . . . 12. . . .3. . . . .4 Condition Variables . . . . . . . . A.6 OverDrawnException. . . . . . . . . . . . . . . . 12. . . .2.3. . . . . .1. . . .java A.java .3. . . . . . . . .1. . . . . . . . . . . A. A. .2. .java . . . . . . . . . . . . . . . . . . . A. . . A. . . 12. . . . . . . . . . . . . . . . . . . . . . . . . . . A.java . . A. . . . . . . . . . . A Listing A. . . . . 120 . . .3 Priorities .1 What is a Thread? . . . . . . . . . . . . . .2. .3. . 11. . .2.

. . .List of Figures 1. . . . . . . An example of a Frame with a MenuBar A menu with MenuItems .2 security architecture . . . . . .1 Graphical interface of serialver . .3 7. . . . . . . . . . Contents of an AccountInputStream file . . . . . . . . . . . . . .5 5. . . . . . . . . . . . . .1 5. A RolloverButton example . . . . . . . . . . . . . . A TextField component .2 7. . . Container managed by FlowLayout . The model/view/controller architecture Event source and listeners . . . . . . . . . . A Java calculator . . . . . . . . . . . . . . . . . . . . . Container managed by BorderLayout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12 5. . . 119 vi . . . . . . . . . . . . . . . . . . . . . . . . . . An example of using font . . . . . . . . . . Container managed by GridLayout . . . . . . . . . . . . . . . . . . . . . .2 3.11 5. . . . .3 4. . Notifying listeners . . . . . . . . . . . . . . . . . . . . . . . . A List component . . . . . . . . . . . . . . . . . . . . .8 5. . . . . . . . . . . . . . . . . . . . . . . . . . . .1 3. .1 9. . . . . . . .2 5. . . . . . . . . . . . . . . . . . . . . . . . . . . . .4 The JDK 1. . . . . . .4 7. . . . . . . . . . .1 7. . . . Instantiation . . A Checkbox component . .4 5. . Stream chaining example . . . . . .2 3. . 3 7 24 25 35 44 51 52 53 54 55 58 59 60 61 64 65 67 68 75 76 78 82 88 101 103 106 109 10. .2 9. . . . . . . . . . PrettyPanel with a button . . . . . . . . . . . . . InputStream class hierarchy . . . .7 5. . . . . . . . . . Environment settings . . . . . . . Concept of an interface . . . . . . . . . . . . . . . . . .5 9. . . . A typical GUI front end . . . . . . . .6 5. . .10 5. . . . . .1 1. . . . . . . . .3 5. . . . . . . . The cat class hierarchy . . . . . .13 7. A Choice component . . . . . . . . .3 9. . . . . . . . . . . . . . . . . . . GUI produced by AFrame. . . . . . . . . . . . . . . . . . . . . . .9 5. . . . . . . . . . Account class hierarchy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .java . . . . InputStream class hierarchy . . . .1 5. . . . . . . . . . . .

. . . . . . . . . . . . . . . . . . . . . . .3 Flow diagram of AccountServer’s protocol . vii . . . . . . .1 IP address format . . .5 Time/thread graph . .4 12. . . . . . . .2 Interaction between ServerSocket and Socket . .1 12. . . . . . . . . . . . . . . . . . . Life cycle of a thread . . . A modifed flow diagram of AccountServer’s protocol A race condition . . . . . . . . All rights reserved. . . . . . 126 12. . . . . . . . . . . . . . . . . 139 144 145 152 161 Copyright c July 1999 Lee Chuk Munn. . wait() and notify() interaction . . . . . . 123 11. . . . . . . . . . . 121 11.LIST OF FIGURES 11. . . . . . . . . . . . . .2 12. . . . . . . . .3 12. . . .

. . . . . . . . . . . . .6 3. . . . . . . . . . . . . . .3 2. . . . . . . .1 2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2 2. Bitwise operators . 104 viii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . AWT event list . . . . . . . . . . . . . . . . . . . . .1 9. . . . .1 9. . . . . .2 List of Java reserved words Binary operators . . . .List of Tables 2. . . .4 2. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1 7. . . . . . .5 2. . Input stream classes . . 8 10 11 12 12 13 31 48 79 Method and member accessibility . . . . . . . . . 102 Output stream classes . . . Assigment operators . Relational operators . . . . . . . . . . . . . . . . .1 4. . . . . . . . . . . . . . . Conditional operators . Differences between abstract class and interface .

network savvy. interpreted. Java can be describe as follows: 1. One of the goals of Java is to enable the construction of software that can run standalone in small machines. portable. confusing features of C++ that brings more grief than benefit. high performance. it also dramatically cuts down on bugs.1.1 Simple What exactly do we mean by simple? The Java designers had the following objectives in mind: • Java was designed to be programmed easily without a lot of esoteric training. multiple inheritance. By virtue of having automatic garbage collection the Java language not only makes the programming task easier. lets take a look at what it is trying to say. Since the sentence is loaded with so many buzzwords. robust. dynamic language.1 What is Java? Java: A simple. • Another aspect of being simple is being small. poorly understood. architecture neutral. 1 . object oriented. • Java omits many rarely used. • Automatic garbage collection for simplifying the task of Java programming. A common source of complexity in many C and C++ applications is storage management: the allocation and freeing of memory. These omitted features primarily consist of operator overloading.Chapter 1 Introducing Java 1. secure. and extensive automatic coercions. multithreaded.

Java enables the 2 Copyright c July 1999 Lee Chuk Munn. Java has true arrays.1. with extensions from Objective C for more dynamic method resolution. The single biggest difference between Java and C/C++ is that Java has a pointer model that eliminates the possibility of overwriting memory and corrupting data.1. This could not be further from the truth. a lot of emphasis has been placed on security. 1.Secure 1.6 Secure Java is intended for use in networked/distributed environments. Instead of pointer arithmetic. 1. 1. .3 Network Savvy Java has an extensive library of routines for coping easily with TCP/IP protocols like HTTP and FTP. Object-oriented design facilitates the clean definition of interfaces and makes software component and reuse a reality. A byte coded class file contains all the necessary information that the Java interpreter or Java Virtual Machine (JVM) needs to run. One of the advantages of a strongly typed language like Java is that it allows extensive compile-time checking so bugs can be found early. Java applications can open and access objects across the net via URLs with the same ease that programmers are used to when accessing a local file system. “Object orientedness” is a matter of technique. The class file can be executed on whatever native platform that JVM has been ported to. delivering a set of well defined library that is easy to learn and use. experience and personal preference. This allows subscript checking to be performed. 1. Toward that end.5 Robust Java puts a lot of emphasis on early checking for possible problems. This makes creating network connections much easier than in C or C++.6 • Finally. 1.1.1. and eliminating situations that are error prone. All rights reserved.1.1. later dynamic (runtime) checking. The object-oriented facilities of Java are essentially those of C++. training.4 Interpreted The Java compiler generates byte codes instead of native machine code. A common misconception is that using an object oriented language like Java makes your program object oriented.2 Object Oriented Object-oriented design is a technique that focuses design on the data and on the interfaces to it.

The JDK 1. Security manager The security manager is the primary interface between the core API and the operating system. Remote Class Signed Class Local Class Bytecode Verifier Core API Class Loader Security Core Java API Package Key Database Access Security Manager Controller Operating System Figure 1. Security package The security package forms the basis of authenticating signed Java classes.1: The JDK 1. Core classes are not subjected to the bytecode verifier’s scrutinity. 3 .6 construction of virus-free.1. tamper-free systems. Key database A database to store keys used by the security manager and access controller to verify the digital signature in signed class files.2 security architecture Security has been further beefed up with the release of JDK 1. the security manager works in tandem with the access controller.2. Access controller The access controller allows or prevents access to the operating system. Elements of the security architecture or sandbox comprises of the following: Bytecode verifier The bytecode verifier ensures that the Java class files follow the rules of the Java language.1) is an extension of the JDK 1. In JDK 1.2. All rights reserved.2 security architecture (see figure 1.2. Copyright c July 1999 Lee Chuk Munn. The access controller is only found in JDK 1. The JVM defines a “sandbox” where the user can safely and securely download and use Java classes. Class loader Loads classes that are not found in the CLASSPATH.Secure 1.1.

there are no “implementation dependent” aspects of the specification. 1 see http://java.10 The Java security architect.com/javaone/sessions/slides/TT03/index. int always means a signed two’s complement 32 bit integer. 4 .1.1. Java security != applet containment 1.html. To enable a Java application to execute anywhere on the network. there are situations where higher performance is required. Java performance will continue to gain ground against native applications. component security != overall system security 5. but there’s more to it than that.sun. Unlike C and C++.1. so the actual process of generating machine code is generally simple. Copyright c July 1999 Lee Chuk Munn. networks are composed of a variety of systems with a variety of CPU and operating system architectures. With the imminent release of the “HotSpot” JVM. Li Gong presented1 the following 5 equations which is useful for understanding Java security.7 Architecture Neutral Java was designed to support applications on networks. given the presence of the Java runtime system. 1.1. The bytecodes can be translated on the fly (at runtime) into machine code for the particular CPU the application is running on. For example. 1. Rather.8 Portable Being architecture neutral is a big chunk of being portable.9 High Performance While the performance of interpreted bytecodes is usually more than adequate. correct security model != bug free implementation 3. testing != formal verification 4. security != cryptography 2. and float always means a 32-bit IEEE 754 floating point number. All rights reserved. The Java compiler does this by generating bytecode instructions which have nothing to do with a particular computer architecture. the compiler generates an architecture-neutral object file format–the compiled code is executable on many processors. The bytecode format was designed with generating machine codes in mind. In general. 1.High Performance 1. they are designed to be both easy to interpret on any machine and easily translated into native machine code on the fly for performance.

1.2 1. The “program” name is HelloWorld.println("hello world"). Copyright c July 1999 Lee Chuk Munn. For example. Classes in Java also have a runtime representation. Java has a sophisticated set of synchronization primitives that are based on the widely used monitor and condition variable paradigm.2 First Java Program No programing language introduction is complete without an attempt at the hello world program. public class HelloWorld { public static void main(String[] args) { System. Notice that Java program statements are terminated by “. The import tells the Java complier that the program will be using routines in the java.1.java.11 Dynamic Language The Java language was design to adapt to an evolving environment.*. 5 . This line defines the actual “program”. Unfortunately.”. writing programs that deal with many things happening at once can be much more difficult than writing in the conventional single-threaded programs. The contents of this program is those within its curly brackets. } } Here is a line by line commentary of the above program. line 2. This is a comment line. All rights reserved. Comments are preceeded by a //. 1. It must be save in a file called HelloWorld. We will not be an exception to this rule. line 1. By integrating these concepts into the language (rather than only in classes) they become much easier to use and are more robust. Lets take a look at a Java program.lang library. line 3. even from across the network.10 Multithreaded Multithreading is a way of building applications with multiple threads. Java only loads classes as they are needed. There are ofcourse exception to this rule.lang.1. Classes are essentially self describing making it possible to dynamically link classes into a running system.First Java Program 1. 1 2 3 4 5 6 7 // Customary hello world program import java.out.

a packaging utility call jar and others. C header files These header files are mandatory for interfacing a Java program with a C program or vice versa.java Correct any errors reported by javac and recompile. line 5. Javasoft provides a free reference implementation of the JDK on its website2 . containts the following: tools Tools include a Java compiler. supporting libraries and perhaps documentations. which we will be using. 2 see http://java. you will need a compiler. The Javasoft’s JDK. a debugger. Use your browser and open docs/index. 6 . Collectively these are known as the Java Development Kit or JDK. a JVM. the JDK sources are available as part of the distribution. The main function is the entry point of this program. we invoke the Java compiler (javac) like so: javac HelloWorld.class file. library The standard library is found under the lib directory and is distributed as a ZIP file (classes. Recall that class files contain byte code and can only be executed by the the JVM. All rights reserved. main contains exactly one line of code and it prints out the hello world message.2. A successful compilation will produce a HelloWorld.zip) documentations The documentations can be found under the docs directory.2 line 4. Now you are ready to execute this program. demonstrations Demo programs are found under demos.html.Java Development Kit 1.com/products/jdk Copyright c July 1999 Lee Chuk Munn.1 Java Development Kit To develope and deploy Java applications. sources Yes. a JVM. 1. We will not be covering JNI in this course. To compile the program. To execute HelloWorld. a documentation extractor.2. This is call Java Native Interface or JNI for short.class do the following java HelloWorld and the string “hello world” should be displayed.sun. Parameters are passed into the program via args which is an array of String.

zip and your current directory in your CLASSPATH specification. Figure 1. Individual class files in a directory..Java CLASSPATH 1. Copyright c July 1999 Lee Chuk Munn.2.2.2 show a generic setting.2: Environment settings Classes can be installed in one of 2 ways: 1. All rights reserved.2 which references your current directory. The directories and files in a CLASSPATH specification should be colon separated on UNIX and semicolon separated on Windows.2 1.zip. You need to include atleast classes.zip:. Again note the “. In a JAR (Java Archive) or a ZIP file.1 JAVA_HOME=c:\jdk1.1 JAVA_HOME=/opt/jdk1.1 CLASSPATH=%JAVA_HOME%\lib\classes. 2. 7 .1 CLASSPATH=$JAVA_HOME/lib/classes.2 Java CLASSPATH The Java tools needs to know where the JDK are located. Witness the classes. the you need to include the archive file name in your CLASSPATH.%PATH% Figure 1. these tools will reference the CLASSPATH environment variable. To do this. If classes are packed in an archive (JAR or ZIP) file.zip file in figure 1. PATH=%JAVA_HOME%\bin. you specify the directory that contains these class files. If your class files are kept in a directory. PATH=$JAVA_HOME/bin:$PATH export JAVA_HOME CLASSPATH PATH On Windows: rem set set set Assume JDK is located in c:\jdk1.” in figure 1.2. On UNIX Bourne shell: # Assume JDK is located in /opt/jdk1.

Integer.Chapter 2 The Java Programming Language 2.1: List of Java reserved words 2. Java defines a numner of types known as primitive data types which are atomic in the sense that these types cannot be broken down into simpler types. These types can be classified into the following groups: 1.2 Primitive Types All data in Java belongs to a particular type. There following is a list of Java keywords. These words are reserved any may not be used in any identifiers (see section 2.3 on page 9). represented as two’s complement 8 .1 Reserved Word Java is a very small and compact language. abstract boolean break byte case catch char class continue default do double else extends false final finally float for if implements import instanceof int interface long native new null package private protected public return short static super switch synchronized this throw throws transient true try void volatile while Table 2.

. String (String). . an underscore ( ). − 231 − 1 long 64 bits. − 27 − 1 short 16 bits. 3. −27 .Identifiers 2. . must be enclosed in double quotes “ .4023E + 45. These forms are shown as follows: 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. . ±3. or a dollar ($) and is followed by any number of letters. Integer types can be represented using decimal. Floating point. −231 . Character (char). if an integer value is immediately followed by the letter “L” or “l” indicates that the integer value is long. ”. 16bit in Unicode. − 215 − 1 int 32 bits. etc. 0x0000 ≤ x ≤ 0xFFFF. underscores. . which are proper types and not pointers. octal or hexadecimal. 2. 5. ±1. Boolean (boolean).79769E + 208 ≤ x ≤ ±4.3 byte 8 bits. . IEEE 754-1985 float 32 bits. 4. Arrays. . which has the value true or false. classes. All rights reserved. . .4028E + 38 ≤ x ≤ ±1. 9 . Furthermore. valid • $money$. We will look at arrays in page 19. you can indicate a floating point number to be either float or double by appending either the letter “F” or “D” to the number respectively. − 263 − 1 2. A valid identifier is one that begins with either an letter. −263 . −215 . . methods.9406E − 324. 6. dollars or digits. The following is a list of valid and invalid indentifiers: • thisLine.3 Identifiers Identifiers are used as meaningful and easy to remember names to members(variables). constants. valid Copyright c July 1999 Lee Chuk Munn. double 64 bits.

invalid To declare and use and identifier. 2.". 2 + -3 10 Copyright c July 1999 Lee Chuk Munn.2 String Concatenation Strings can be concatenated using the plus operator (+). All rights reserved.4 • toBeOrNotToBe. 2.4. Operator + ∗ / % Use op1 + op1 op1 ∗ op1 / op1 % op2 op2 op2 op2 op2 Result adds op1 to op2 subtracts op2 from op1 multiplies op1 by op2 divides op1 by op2 compute the remainder from dividing op1 by op2 Table 2.1 Binary Operators Binary operators take two operands and returns a result. String msg = "There are " + days + "in a leap year. 2.3 Unary Operator Unary operators changes the sign of a value or variable. we have to preceed it with a type. .2: Binary operators 2.4 Operators If you are familar with either C or C++ operators then you will feel right at home with Java operators. int foo. We will also initialize bar with the value of 100.4. The code snippet below illustrates this. Please refer to table 2. Lets declare an identifier called foo and bar which are of type integer (int). valid • $12345. valid • 123isAsEasyAsABC.4.Unary Operator 2.2. bar = 100.4.

Bitwise Operators

2.4.8

2.4.4

Increment and Decrement Operators

Increment and decrement operators can be used as short cut to increment or decrement a variable by one. There are two versions of these operator, a prefix and a postfix version. The prefix version implies that the increment or decrement should be perform first before any other operation while the postfix version performs the increment or decrement after the entire expression has been evaluated. The code below
1

count = ++itemA + itemB--; can be rewritten as follows:

1 2 3

itemA = itemA + 1; count = itemA + itemB; 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 op1 && op2 op1 || op2 !op1 Result op1 and op2 are both true either op1 or op2 is true 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 depending 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 bitwise operators are not as extensive as some languages like C/C++. Please refer to table 2.5.

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

11

Assignment Operators

2.5

Operator > >= < <= == !=

Use op1 > op2 op1 >= op2 op1 < op2 op1 <= op2 op1 == op2 op1 != op2

Result true iff op1 true iff op1 true iff op1 true iff op1 true iff op1 true iff op1

is is is is is is

greater than op2 greater or equal to op2 less than op2 less or equal to than op2 equal to op2 not equal to op2

Table 2.4: Relational operators Operator >> << >>> & || ^ ~ Use op1 >> op2 op1 << op2 op1 >>> op2 op1 & op2 op1 || op2 op1 ^ op2 ~op1 Result shift bits of op1 right by a distance of op2 bits, sign preserving shift bits of op1 left by a distance of op2 bits, sign preserving shift bits of op1 right by a distance of op2 bits, non sign preserving bitwise AND op1 with op2 bitwise OR op1 with op2 bitwise exclusive OR op1 with op2 complements op1

Table 2.5: Bitwise operators

2.4.8

Conditional Expression Operator

We can use conditional expression operator to selectively evaluate portions of 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 increment of 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

Comments

2.5.1

Operator += -= ∗= /= %= <<= >>= >>>=

Use op1 += op2 op1 += op2 op1 ∗ = op2 op1 /= op2 op1 %= op2 op1 <<= op2 op1 >>= op2 op1 >>>= op2

&= |= ˆ=

op1 &= op2 op1 |= op2 op1 ˆ= op2

Result increment op1 by op2 decrement op1 by op2 multiply op1 by op2 and assign the result to op1 divide op1 by op2 and assign the result to op1 the remainder of the division is assigned to op1 left shift op1 by a distance of op2 and assign the result to op1, sign preserving right shift op1 by a distance of op2 and assign the result to op1,sign preserving right shift op1 by a distance of op2 and assign the result to op1, non sign preserving bitwise AND op1 by op2 bitwise OR op1 by 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 statements 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 comments aids 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

if-else Statement 2. space and new lines are recommended to make the program readable. Java program statements are terminated with a semicolon (. 2. A block is a group of statements enclosed within a pair of curly brackets ({}). Liberal use of what space such as tab. 14 . The syntax of the if-else statement is: if <condition> <statement_1> [ else <statement_2> ] If the <condition> is evaluated to true. Documentation comments is a variation of delimeted comments.. . The following example illustrates the use of this statement: 1 2 3 4 5 6 char grade. 3.3 if-else Statement The if-else statement provides your programs with the ability to selectively execute other statements based on some criteria.∗/ are treated as comments and can be extracted as documentation by the javadoc tool. . All rights reserved. .. if (score > 90) { grade = ’A’. Blocks and Whitespace Java is a context free langage unlike languages like COBOL where character position matters. <statement_1> will be execute otherwise do <statement_2>. Variables define within a block is not visible outside of the block. Delimited comment used /∗ and ∗/ to enclose the comments like so: count = item /∗ from stock ∗/ + count.2 Semicolons. count = (count > MAX)? 0: ++count. } 2. All text between /∗∗ . int score. 1 2 3 4 { int count.5.5.5. Statements within a block is treated as if it were a single statement. You do not need to terminate block statements with a semicolon. count is not available outside the block. In the following example.). Copyright c July 1999 Lee Chuk Munn.3 2.

out. break. } else if (score >= 60) { grade = ’D’. the expression must evaluate to an integer type.out. } Note that the else clause if option which means that if the condition is not met. an action is not taken.4 switch-case Statement Use the switch statement to conditionally perform statements based on some expression. If the following example: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 int month. switch (month) { case 1: System. 15 .println("March"). The following code snippet will only print out the message “excellent!” if the score is 90 and above: 1 2 3 4 .println("February"). .println("excellent!"). .out.out. case 2: System. You can think of switch as a compound if-else statement. break. . } else { // Everybody below 60 fails grade = ’F’. . Copyright c July 1999 Lee Chuk Munn. case 3: System.5. if (score > 90) System. break. case 4: System. break.out.5. . All rights reserved. .switch-case Statement 2. .println("April").out. .println("May"). } else if (score >= 70) { grade = ’C’. break.4 7 8 9 10 11 12 13 14 15 16 } else if (score >= 80) { grade = ’B’. case 5: System. 2.println("January").

The break statements cause control to break out of the switch and continue with the first statement following the switch.println("November"). . 16 . The break statements are necessary because case statements fall through. case 11: System. case 9: System.out. break.println("June").out. .println("September"). break.println("July"). All rights reserved.println("Not a valid month"). case 12: System. . The default acts as a catch all if month is not in the specified range. then an appropriate month will be printed otherwise a Not a valid month message will be printed.out. The general syntax of the switch statement is as follows: switch <condition> case <value_1>: <statement_1> .out. case 10: System. break. case <value_2>: <statement_2> .switch-case Statement 2. .out. Copyright c July 1999 Lee Chuk Munn. without an explicit break control will flow sequentially through subsequent case statements.5. case 7: System. case 8: System. The default and break are optional.println("August"). break. . break. default: System. That is.out. break.println("December"). break. break. break. .out. } If month falls in the range of 1 and 12. .println("October").out.4 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 case 6: System.

. 17 .read() != -1) { count++.5. . while <expression> is true. the do-while is convenient to use when the statements within the loop must be executed at least once. The syntax of the while statement is: while <condition> <statement> That is. <increment>) <statement> The following example uses a for loop to sum all numbers in the range of 1 to 100. while (input. <expression>. The syntax of for loop is: for (<initialization>.5. . termination criteria. Copyright c July 1999 Lee Chuk Munn.out.5. 2. <statement> can be a single statement or a block. For example.println("characters read = " + count).7 for Statement Use the for loop when you know the constraints of the loop (its initialization instruction. do <statement>. which is similar to the while loop you have met earlier except that the expression is evaluated at the bottom of the loop: do { <statement> } while (<expression>).7 [ default: <default_statement> ] 2. An example of the while statement is as follows: 1 2 3 4 5 6 .5 while Statement Generally. . 2.5. System. } . and increment instruction).for Statement 2. All rights reserved. a while statement performs some action while a certain condition remains true.6 do-while Statement The do-while loop. The do-while statement is a less commonly used loop construct in programming but does have its uses.

break, continue and Label Statement

2.5.8

1 2 3 4

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

2.5.8

break, continue and Label Statement

The following keywords are used to control program flows within loop statements. A label is used to identify a particular statement. Label names follows identifiers (see section 2.3 on page 9) naming conventions. The syntax of a label is as follows: <label>:<statement> We have seeen the break statement within the switch statement; recall that the break causes the flow of control to jump out of the switch statement. Another form of the break statement causes flow of control to break out of a labeled statement. The break statement has the following syntax. The <label> is optional. If <label> is not present, break will break out of the “closest” loop. break [<label>]; While a break breaks out of a loop, a continue causes control to be transfered back to the loop for re evaluation. As with break, continue has the label and unlabelled form. continue [<label>]; Lets examine a code snippet to see break, contiune and label statements in action.
1 2 3 4 5 6 7 8 9 10 11 12 13 14

outer_loop: while (a > MAX) { if (testIt(a)) { a++; continue; // Note this } else { for (int j = 0; true; j++) { a = compute(j, a); if (a > j) { continue; // Note this } else if ((a > 0) && (a < j)) { continue outer_loop; // Note this } else { break outer_loop; // Note this }
Copyright c July 1999 Lee Chuk Munn. All rights reserved.

18

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 while loop in line 1. line 9, Since there are no label following the continue, control will go back to 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. Control will be transfered to line 18.

2.5.9

return Statement

A return is used to exit from a method. The general syntax of return is as follows: return [ <value> ]; A return with a value returns the value to the caller of the method that we are currently leaving.

2.6

Array

Like most programming language, Java allows you to collect and manage multiple values through an array. The following is a declaration of an integer array called intArray. int[] intArray; Note the square brakets ([]) indicates an array. Once you have declared an 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 we use the new keyword. We will now create intArray with 10 elements. The desired 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

Multidimensional Array

2.6.1

Every array has a property called length. length returns the number of elements in an array. length is not present when an array is not created.
1 2 3

int[] intArray = new int[100]; for (int i = 0; i < intArray.length; i++) intArray[i] = i; Another way of creating arrays is with an initializer which looks like the following: 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 are really arrays of arrays. To declare a two dimensional array you use 2 pairs of [] like so: int[][] intArray = new int[10][10]; When allocating a multidimensional array, you do not have to specify the number of elements that are contained in each dimension. For example, the following
1 2 3 4 5 6

int[][] intArray = new int[10][]; for (int i = 0; i < intArray.length; i++) { intArray[i] = new int[i]; for (int j = 0; j < intArray[i].lenght; j++) intArray[i][j] = j; } initializes the array with the following values:

1 2 3 4 5 6 7 8 9 10

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

= = = = = = = = = =

0 0, 0, 0, 0, 0, 0, 0, 0, 0,

1 1, 1, 1, 1, 1, 1, 1, 1,

2 2, 2, 2, 2, 2, 2, 2,

3 3, 3, 3, 3, 3, 3,

4 4, 4, 4, 4, 4,

5 5, 5, 5, 5,

6 6, 7 6, 7, 8 6, 7, 8, 9

You cannot create an inner array without first creating the outer. This is legal: int[][] intArray = new int[10][];
Copyright c July 1999 Lee Chuk Munn. All rights reserved.

20

Return types can be any valid Java type which includes all primitive types. 1. 3. 9} }. . {0. 7}. A method has the general syntax: public <return_type> <name>([<type> param_1. {0. foobar(fred). 1 2 3 4 5 6 7 public void fooBar(int input) { input = 7.println("fred = " + fred). {0. 3. 5. 4. Multidimenstional arrays can also be allocated and initialized with nested initializers. 6. 4}. {0. 8. 5}. 5. 1. // fred = 0.Defining Methods 2. 5. Method parameters are passed by-value viz.1 but not this: int[][] intArray = new int[][10]. 6}.out. 3. All rights reserved. 1. 1. 3. {0. 6. 1. 8}. 1}. 2. To return a value we use return with the desired value when we wish to exit the method. 3. 4. 3}. . 7. 7. . 2}. 2. 2. Copyright c July 1999 Lee Chuk Munn. Although we pass fred into fooBar() to be modified the value remains unchanged once fooBar() has completed execution. 2. rewriting the example in page 20 produces the following: 1 2 3 4 5 6 7 int[][] intArray = { {0}. 4. 4.]) { <method_body> } The <return_type> is the type returned by the the method. System. 4. 1. 1. . arrays and references. int fred = 0. 2.7. 21 . 2. {0. {0. . 3.7 Defining Methods Methods object oriented way of saying functions. 6. 5. 2. 1. } . {0. any modification done on the formal parameter will not affect the actual parameter. For example. {0. 2.

A Java program without a main() will not run. All rights reserved. 22 . the method that the JVM will call first when we execute a Java program.7.7.1 2. The signature of main() is as follows: public static void main(String[] args) { . . .} The args is an arrays and is used to store command line parameters.main Method 2. If we 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.1 main Method The main() method name is usually reserved for the main entry point of Java programs viz.

1 Object Concepts What is an Object? There are many definitions of objects. • Increase software reuse. rules: Prolog) or mathematical methods (functional programming: ML.1 Why the Hype? Object-orientation is a new technology based on objects and classes. design. providing the desirable property of seamlessness between activities. It presently represents the best methodological framework for software designers to develop complex large scale systems. Lisp). For this course. • Easier maintance. Objects provide a focus throughout analysis. and interaction of objects in its models.2. The benefits of object orientation are obvious.Chapter 3 Object Orientation 3. 3. some of the benefits are listed below: • Faster development by breaking down complex systems to managable chunks. • Enhanced modifiability to adapt to changes. The use of objects distinguishes object-orientation from other techniques such as traditional structured methods (process-based: data and function are separate) or other techniques such as knowledge based systems (logic progamming.2 3. we define an object as follows: 23 . and implementation by emphasizing the state. • Increased quality. behavior.

1.What is Encapsulation? 3. processes are dynamic copies of programs just as an object is a dynamic copy of a class. The object oriented way of tackling this problem is encapsulation. ClassA instantiate =⇒ ObjectA Figure 3. etc. We can use properties to classify and object as well as to use properties to denote the current state of an object. This is because we implement parts of the system based on the implementation of another part. But a car/road would not fit our defination. 3. From figure 3. ObjectA is instantiated from ClassA and is said to be an instance of ClassA. 3.2. Properties of a cat includes the following non exhaustive list: type of cat. behaviour and identity with a well defined role in a problem space.1: Instantiation 3. The act of creating an object from a class is called instantiating and the instantiated object is called an instance of a class. The key in object orientation is to be able to identify objects and how to partition entities in a problem space into objects. You would for instance define a car as an object or a road as an object since both have clearly defined boundry. All rights reserved. 24 . anything with a clearly defined boundry.2. Another difficulty with large software is that often a minute change to one part of the system requires changes to every other parts. So how do you define objects? In general.2.4 Object An entity which has state.3 What is a Property? A property is a single public attribute. How do class and object differ? Think of classes as programs and objects as processes.4 What is Encapsulation? One of the main difficulties when dealing with complex software is the level of implementation details. A class can be defined as follows: Class A class is a set of objects that share a common structure and a common behavior.2. size. Very often we are overwhelmed by them that we do not know where to begin.2 What is a Class? A class is a template for objects. hiding what is not necessary so that we can concentrate on what is the issue at hand: Copyright c July 1999 Lee Chuk Munn. color.

Consider the following class hierarchy shown in figure 3. You will not regret it. All rights reserved.2. abstract is ignoring them altogether.2.6 What is Inheritance? Inheritance is a relationship between classes where one class is the parent class of another.2. Sometimes. it is a stuff tiger to be exact.What is Inheritance? 3. 25 . inheritance can also have the notion of specialization. Mention the word “car” and most of use will have the mental image of a metalic body with wheels that travels on roads.2: The cat class hierarchy Besides the “is-a” relationship.5 What is Abstraction? While encapsulating is hiding away details. We have abstracted the notion of a car to its purest form ignoring other details. We use abstraction everyday to help us focus on a particular subject. inheritance is also know as an “is-a” relationship. Inheritance can be defined as: Inheritance Properties or characteristics received from an ancestor. Tiger Cat Lion Figure 3. In figure 3. Inheritance encourages reuse and simplifies code development.7 Encapsulation The principle of hiding design or implementation information that are not relevant to the current object. 3.2.2 we see that Hobbes1 is a specialization of tiger. 1 → Hobbes Copyright c July 1999 Lee Chuk Munn. Abstraction The principle of ignoring those aspects of a subject that are not relevant to the current purpose in order to concentrate more fully on those that are. For those who do not know what Hobbes is should buy a copy of SCMP and check out the comics section. 3. We may not have imagined a driver or even the make and color of the car.

} public void withdrawal(float amt) { if ((amt <= balance) && (amt >= 0)) balance -= amt. 26 . account number. public void deposit(float amt) { if (amt >= 0) balance += amt. } public void transfer(Account from.withdrawal(amt). Refering to figure 3. This class must by save in a file called “Account. we see that a cat object can also be a lion object or a tiger object since cat is the lowest common denominator class of the two.1 3. public float balance. The following is an Account class with name. public boolean overdraft. withdrawal() and transfer() method.Objects and Class 3.3. Account also has the deposit(). a class definition has the following syntax: public class <class_name> { <member_declaration> <methods_declaration> } Classes can contain properties usually modelled by member variables.3. The word polymorphism is a derived from two words: “poly” which means many and “morph” which means forms. All rights reserved. These are also declared as part of the class body. In Java.1 Expressing Objects with Java Objects and Class We know that objects are instantiated from classes so lets look at defining a class in Java.3 3. from. deposit(amt). } } Copyright c July 1999 Lee Chuk Munn. public int acctNo.2.java”.2. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class Account { public String name. float amt) { if (amt < 0) return.7 What is Polymorphism? Polymorphism is the ability of an object to assume many different forms. 3. account balance and overdraft as properties.

overdraft = true. . A constructor must follow the following rules: 1. Note that Account is not a primitive type (see section 2. we can rewrite the code in page 27 as follows: Copyright c July 1999 Lee Chuk Munn. Instantiate an object call fred. balance = 100F. } Now using the constructor. fred. private float balance. 2. line 4 to 7. fred. We call type type of variable reference type.balance = 100F.2 To instantiate an Account object we use new.3. overdraft = false. a constructor is only used during instantiation to initialize the object and is never used again. fred. 3.name = "Fred". 1 2 3 4 5 6 7 Account fred. line 3.2 Constructors and Destructors Constructors are useful for initializing objects before they are being used. private int acctNo. fred = new Account(). . fred. . we “open” an account for Fred. Assign values to object fred properties. The initial value of reference type is null. } . A constructor does not have any return type. In the following code. A constructor’s name must be the name of the class.Constructors and Destructors 3. line 1. Declare an Account variable. 27 .2). private boolean overdraft. . public Account(String n.3.acctNo = 12345. All rights reserved. Constructors are special purpose methods. int no) { name = n. acctNo = no. We can write a constructor for Account as follows: 1 2 3 4 5 6 7 8 9 10 11 12 13 public class Account { private String name. .

if they are not present in an object.3. or a database record or an opened file. These must be properly closed so that the database record is in a consistend state for instance. a destructors is known as a finalizer. In Java.2 Account fred = new Account("Fred". int no) { . We must perform these in the destructors. Destructors are called before the object is grabage collected and its memory released. Every object has a default constructor if one is not provided. Finalizers are optional. Destructors are the exact opposite to constructors. If balance is not 0. . . public Account(String n. 12345). we will save the object otherwise we will discard the object. no finalization will be done.Constructors and Destructors 3. Our finalizer will check if an account object has an savings. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class Account { private String name. private boolean overdraft. Sometimes an object may hold other objects like a network connection. 28 Copyright c July 1999 Lee Chuk Munn. To add a finalizer to an object simply add the following method: protected void finalize() { // perform clean up } Lets add a finalizer to Account class. you lose the the default constructor. The default constructor takes no argument and has an empty body. protected void finalize() { if (balance <= 0) { // save this account } } } There are some additional things to be aware about finalizers: • A finalizer is invoked before the the JVM garbage collects the object. . private int acctNo. } . . All rights reserved. A default constructor has the following signature: public <class_name>() { } Once you created your own constructor. private float balance. The garbage collect cannot do this for us. .

so objects with finalizer may never be called. . 29 . Therefore we cannot know the time or order of the finalizers will be invoked.3 Encapsulation Examining the code snippet on page 27 . .3 • The JVM may exit without garbage collecting objects.3. Lets rewrite Account so that we access its properties through getter and setter instead of directly manipulating the member variables. • the JVM makes no guarantees about when garbage collection occurs or the order of the object will be collected. private int acctNo. furthermore if we decide to change the account name from name to accountName we will have to change every reference to it. Copyright c July 1999 Lee Chuk Munn. . The getter and setter methods has the following “pattern”: public void set<PropertyName>(<PropertyType> value) { .Encapsulation 3. 1 2 3 4 5 6 public class Account { private String name. Clearly we need to hide the implementation details from view. we see that we need to know Account internals to use it. } If the <PropertyType> is boolean. . . } This type of property is know as boolean property. All rights reserved. } public <PropertyType> get<PropertyName>() { . To encapsulate properties we use getter and setter methods. private float balance. private boolean overdraft. . We use encapsulation to achieve this. 3.3. We really need a way of manipulating the properties without knowing how it is done. . 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 only properties respectively. the getter method is replaced with the following method signature: public boolean is<PropertyName>() { . . .

Method and Member Visibility

3.3.4

7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

public void setName(String n) { name = n; } public String getName() { return name; } public int getAccountNumber() { return acctNo; } public float getBalance() { return balance; } public void setOverdraft(boolean b) { overdraft = b; } public boolean isOverdraft() { return (overdraft); } } name and overdraft are read/write property while acctNo and balance are read only since we have not provided setter. It is important to recognize what we have done. We have hid implementation details viz. the member names in this case, from the outside world. To reinforce this notion, we changed all member visibility from public to private. A private means that these members are only accessable within the Account class. The benefit we got is: 1. Manipulating properties with setName("Fred") and getName() is much more meaningful than this: fred.name = "Fred"; 2. Changing implementations eg. renaming the variables, will not require massive global changes.

3.3.4

Method and Member Visibility

Encapsulation hides a class internal details for the outside world; if we were to provide getter and setter methods but leave Account class member declaration 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. By using 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 on members or methods:
Copyright c July 1999 Lee Chuk Munn. All rights reserved.

30

Inheritance

3.3.5

public A method or member that is declared public is accessible from any class. protected A method or member that is declared protected is accessible only to its subclass and the class itself. We will examine the notion of subclass in section 3.3.5 on page 31. private A private method or member of a class is only accessible from within that class. Other classes including subclass cannot access this member or method. Table 3.1 summarizes the previous points: Keyword public protected private Self Yes Yes Yes Subclass Yes Yes No Others 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 unless performance is a big issue. You should always encapsulate members with public setter and getter methods. Standard methods that manipulate your class should be made public. • If you have written a class and you want to perhaps give control of your 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 only within your class.

3.3.5

Inheritance
The syntax for

Java uses the keyword extends to denote inheritance. extends is as follows: public <class_name> extends <parent_class_name> { . . .

The parent class is also know as superclass and the child class is sometimes called 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

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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

public class FixedDepositAccount extends Account { private Date term; private float interest; public FixedDepositAccount(String n, int acct) { super(n, acct); term = null; interest = -1F; } public void setTerm(Date t) { // We only allow to set the term once if (term == null) term = t; } public Date getTerm() { return (term); } public void setInterest(float i) { if (interest == -1F) interest = i; } public float getInterest() { return (interest); } } public class SavingAccount extends Account { public SavingAccount(String n, int acct) { super(n, acct); } } When we extends a class, we inherit all visible members and methods. Visible members and methods are those marked with either public or
Copyright c July 1999 Lee Chuk Munn. All rights reserved.

32

All rights reserved. Please refer to the documentation for more information. You can think of super as a “. acct).. super is a keyword in Java. we therefore need to provide constructors for our two child classes. This ensures that the parent constructors gets called. What is the super() in line 6 and 14. We also know that every object has a constructor. The only exception to this rule is the Object itself. This is know as constructor chaining.” in your DOS file system. • Account’s constructor.Inheritance 3. etc. The super(n. But notice that we can still access these variables via the appropriate getter and setter methods. To understand line 6 and 14 we need to delve a little more into inheritace. 33 . But before we can create the object itself the JVM must ensure that the parent is create before the child. equals(). Note that the compiler will only chain to the default constructor of the parent class. So if we write public class Account { the Java compiler will modify the declaration to this: public class Account extends Object { This is to ensure that every object have all the necessary methods like clone().4 later in this chapter. Java only supports single inheritance. We will look into visibility rules in more detail in section 3. This works well if the parent class has a default constructor. But Account does not have a default constructor! We have replace it with our own constructor. It references the parent class. notify(). What have they not inherited? • The private member variables.6 protected. Similary this refers to the current object. In this case we have to do the chaining ourself.3. withdrawal() and transfer().3. To do this the Java compiler will insert a super() as the first line in every constructor. So what has FixedDepositAccount and SavingAccount inherited? A short answer would be all the getter and setter methods as well as deposit(). Object and Constructor Chaining All Java objects inherit Object implicitly. So when an object is instantiated its constructor gets called. Copyright c July 1999 Lee Chuk Munn. is the link to our parent class.

In C. true • fred instanceof Account. We can use the instanceof operator for this purpose. In Java. Account acct = fred. In this case. we need to know exactly what is the actual object. 12345). The general syntax for casting is as follows: <type_a_ref> = (<type_a_class>)<type_b_ref>. Because you can use a parent object reference to hold a child object. If can loose precision if you cast from a wider type to a narrower type eg. the JVM needs to dynamically lookup what fred refers to.6 3. Casting is only permitted between equvalent primitive types eg. we get the following results: • acct instanceof SavingAccount. Java allows you to hold an object with its parent type variable (polymorphic). from long to short. false Casting refers to converting from one type to another. from int to long or from float to double. From a child class to a parent class.3.3. casting goes through strict runtime checks to ensure that you are not violating security rules. Casting between objects is much more interesting. Although this incur a small overhead but the benefit far outweighs the performance hit. instanceof will return true if the object on the left hand side of the operator is an instance of the right hand side class. So we can do this: Account fred = new SavingAccount("Fred". 3.6 Polymorphism Like most object oriented programming language. we can have three possible situations: 1. All rights reserved. From a parent class to a child class. a char * can be cast to almost anything. Copyright c July 1999 Lee Chuk Munn. true • fred instanceof SavingAccount. Consider the following: 1 2 3 FixedDepositAccount foo = new FixedDepositAccount("Foo". 34 . Using instanceof of fred and foo. 12345). SavingAccount fred = new SavingAccount("Fred". Subsequently when we use fred. true because Account is the parent class of SavingAccount • foo instanceof SavingAccount. 67890). Between siblings.Polymorphism 3. 2.

3.). Furthermore the cast is check during runtime to ensure that what we are casting to is the correct type.3. 2. SavingAccount save = new SavingAccount(..3: Account class hierarchy Lets look at the Account hierarchy again as show in figure 3. Account acct. Casting between siblings is illegal and will never compile. acct = save.Overriding 3..7 FixedDepositAccount Account SavingAccount Figure 3. 3. Casting an object can be divided into the following three cases: 1. save = (SavingAccount)foo. Assigning a superclass to a subclass (down cast).). 35 . We will override this method in FixedDepositAccount. The following is illegal. Otherwise you will get a ClassCastException error.7 Overriding When a subclass defines a method with the exact same name and signature as a method in its super class it is said to override the superclass method. We must therefore modify the behaviour of withdrawal(). save = (SavingAccount)acct..3. This requires the cast operator otherwise it would not compile.. Assigning a subclass to a superclass (up cast) can be done with a simple assigment. FixedDepositAccount does not allow withdrawal until the term matures. Copyright c July 1999 Lee Chuk Munn. But since we have extended Account which allows withdrawal. Overriding is used to customize a superclass method. All rights reserved. We have the following objects: 1 2 3 FixedDepositAccount fixed = new FixedDepositAccount(. 3. The JVM will check acct during runtime to make sure that acct is actually referencing a SavingAccount object.

. We can override override superclass’ methods and members.withdrawal(amt).3. but if it has we then allow the withdrawal. Line 16 calls the superclass’ withdrawal() by prefixing it with a super. 3. declare a member with the same name and type in the subclass. then we will not do anything. private float interest. it will automatically assign one.3.Overloading 3. we override withdrawal() so that it will check if the term has matured. We now can withdraw the entire amount or portion of our balanance depending on the method we use. term = null. To overriding a member. The code to implement the new functionality is as follows: Copyright c July 1999 Lee Chuk Munn.8 Overloading Overloading is commonly used in Java to define a number of related methods with the same name but different signature. Overloading allows us to tailor a method to different use as we shall see in withdrawal() method. We will now add more capabilities to FixedDepositAccount. 36 . You can also overload constructors. • Add an extra constructor such that if no account number is give. Similarly you can access the overridden superclass’ member by prefixing a super. int acct) { super(n. } } Notice that in line 12. If it has not. Armed with overloading. .after(term)) super.8 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class FixedDepositAccount extends Account { private Date term. acct). // If mature then we allow withdrawal if (today. public void withdrawal(float amt) { Date today = new Date(). All rights reserved. • Add an additional withdrawal() that withdraws the entire amount. } // setter and getter methods for term and interest . interest = -1F. public FixedDepositAccount(String n.

public FixedDepositAccount(String n. Invoking an overridden method or member. . All rights reserved. . } . 17. term = null. Lets summarize what we have learnt: 1. You only need to supply the account name.3. . acct). int acct) { super(n. . This withdrawal() method withdraws the entire balance from the account.super and this 3. . public void withdrawal(float amt) { .9 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class FixedDepositAccount extends Account { . ) to invoke a constructor in the current class. We use getBalance() which we have inherited from Account to get the full balance. 2. Now using withdrawal(float amt) method. . ).abs((new Random()). ). . Of course the withdrawal is subject to the usual checks. Invoking current class’ constructor. Use this( . } public void withdrawal() { withdrawal(getBalance()). . 3. Invoking superclass’ constructor. Use super( .9 super and this We have seen the use of super and this over the last few sections. 37 Copyright c July 1999 Lee Chuk Munn. Math. Recall that we use super( . } The following is an explanation of the above code snippet: line 9. Similarly we use this( . . . line 16. Notice that we use a random number generator to generate an account number.3. 3. . interest = -1F. we withdrawal the entire amount. Use super. . line 10.nextInt())). . Again this() must be the first line in a constructor. This is the overloaded constructor. . } public FixedDepositAccount(String n) { this(n.<method>. . ) in page 33 to chain the superclass’ constructor.

} .count = count. Note that the final keyword does not alter the signature of the method. . The this keyword can also be used to disambiguate the context. . Consider the following code: 1 2 3 public void fred(int count) { this. 38 . A final member is a member whose values you cannot change once you have assigned a value to it. to prevent users form arbitrarily changing your interest rate calculation. } public final void withdrawal() { withdrawal(getBalance()). . .final Keyword 3.4 final Keyword You can use the final keyword on classes.<method> or just this which refers to the current instance. Below is a code snippet from FixedDepositAccount which we have looked at previously.count refers the the instance member while count refer to fred’s formal parameter. A class declared with the final keyword cannot be subclassed. . like this. Actually. Copyright c July 1999 Lee Chuk Munn. If we do not want others to override our withrawal() methods. For example. If we have the following declaration: public final double PI = 3.4 4. .414. } The this. . . you declare the method as final. all instance methods and members have an implicit this preceeding them. 1 2 3 4 5 6 7 8 9 10 public class FixedDepositAccount extends Account { . 3. All rights reserved. A final method cannot be overriden by subclasses. we add the final keyword as below. public final void withdrawal(float amt) { . methods and members. Use this. you have a method that calculates interest retes. A final class is declared as follows: public final class Fred { . Refering to current class. This is to prevent subclass from changing the functionalities of your method.

12345). acctNo = acct. } . If we have a final member whose type is an object like so: public final Account fred = new Account("Fred". .deposit(200F). All rights reserved. private final float balance. If you don’t. If you decide to declare a final member without an initialize. the Java complier will complain this as an error. 3. date = new Date(). When you declare a final member.getBalance(). withdrawnAmount = amt. Therefore the following is permissible: fred. for instance: public class OverdrawnException extends Exception { private final String name. then we cannot change the member itself but we can change the content of the member. fred = new Account("Barney". private final float withdrawAmount. . private final int acctNo. So while reassigning a value to fred is not permissible. you have to provide an initializer to the member. You can declare a member in a class to be global by adding a static keyword in its declaration. public OverdrawnException(Account acct. Changes to a global variable can be seen globally.5 static Keyword In most programming language.static Keyword 3. private final Date date. fred. Copyright c July 1999 Lee Chuk Munn.getName(). you have the concept of global variables. 23456). 39 . float amt) { super("Overdrawn"). a global variable is ”visible” from every part of a program. call a method in Account to modify its member is permissible. balance = acct.5 then PI’s value cannot be changed.getAccountNumber(). name = acct.withdrawal(100F). then you will have to initialize that final member in the class’ constructor.

System. System. all instance references 1 copy of this member. This can potentially cause data corruption. So. Foo barney = new Foo(). 1 2 3 4 5 6 Foo fred = new Foo(). So if an instance modifies a class member. The name member is known as an instance member because if we change this member.println("fred = " + fred. Consider the following simple class which consists of 1 member: public class Foo { public String name. } Now we instantiate 2 instances of this class and perform some operations on them.name = "Fred Flintstone". then that assigment should only affect fred. This is an extremely good approach to sharing information between instance. as the name implies.5 Let’s take a look at what a non-global member in Java terms first before we look at what a global member is. local to that instance.out. for example.name). both the output will be “Barney Rubble”. we make that member to be a class member . 40 . What is going on here? The reason is because when we declare any member with static. barney.name = "Fred Flintstone". Similarly for barney. “Fred Flintstone” (line 5 ) and “Barney Rubble” (line 6 ). } If we were to run the previous sequence of statement again. we can use the following method: Foo. We will address this issue in section 12. if we assigned “Fred Flinstone” to fred. fred. Now consider adding static to Foo like so: public class Foo { public static String name.5. we can declare it in the following way: Copyright c July 1999 Lee Chuk Munn. What do you expect the output from lines 5 and 6 to be? The answer should come as no suprise. therefore. You do not have to instantiate an instance of a class to use its class member.out. to declare a π constant.static Keyword 3. its modification is visible to every other instance of the same class.println("barney = " + barney.name).name. All rights reserved.name = "Barney Rubble". the change will only affect that particular instance viz. We can combine final and static to declare “constant”. We can reference a class member by preceeding the member’s name with the its class’ name. if we want to reference name. But you have to ensure that 2 or more instances do not modify a class instance simultaneously.

therefore using this would cause the Java compiler to complain. public static double circumference(double radius) { return (2 * PI * radius). In fact. Can you explain why when we print “Hello World” to the console we perform the following: System. constants declared in the following manner throughout the JDK. Similarly. this refers to an instance. a class method is declared with the static keyword. } } There are a few points that you need to remeber about class method: 1. as with class member.414.1). You cannot use this inside a class method.out. you do not have to instantiate the class. . } So you can use PI in the following manner: double circumference = 2 * Circle. 2. All variables and members used in a class method are assumed to be declared with static. I can use circumference() in the following way: double myCircle = Circle.println("Hello World"): 41 Copyright c July 1999 Lee Chuk Munn.5 public class Circle { public static final double PI = 3. see the Double class in java. For an example. The following example illustrates this: 1 2 3 4 5 6 public class Circle { public final double PI = 3. the compiler will flag it as an error. To use a static method.static Keyword 3. If you try to use an instance inside a class method. you can declare class methods.lang package.PI * radius. Therefore. } } Line 4 is an error because PI in line 2 is declared without a static. All rights reserved. since a class method is not in an instance.414. public static double circumference(double radius) { return (2 * PI * radius).circumference(2. The following is a class method declaration: 1 2 3 4 5 6 public class Circle { public static final double PI = 3. just preceed the method name with its class name.414.

Chapter 4 Abstract Class and Interface 4. } To use an abstract class.). We want to add printing capabilities to Account. Obviously the amount of information printed out by different Account subclass are different.1. Mark unimplemented methods with the abstract keyword. The general syntax for declaring an abstract class is as follows: public abstract class <class_name> { public abstract void <method_name>(.. Denote the class as abstract with the abstract keyword in the class declaration. There are incomplete because when writing the class the behaviour of a method cannot be determine. • You cannot instantiate an abstract class. the subclass itself is an abstract class.1 Defining an Abstract Class To declare a class to be abstract. Abstract methods do not have body. Consider the Account class from the previous chapter. we extends it and override those abstract methods by providing them with implementation. so when we 42 .. Note also the following points about abstract classes: • If a subclass does not implement all abstract methods of its superclass. 2.1 Abstract Class Abstract classes are incomplete classes. 4. we do the following: 1. Abstract can contain non abstract methods.

out. we mark printAccount() as abstract. int no) { . } . .println("Mature on = " + getTerm()).println("Amount deposited = $" + getBalance()). We will now have to rewrite FixedDepositAccount and SavingAccount to implement printAccount(). . But we do want to point out to anyone inheriting Account that they do need to consider printing. public Account(String n. The following code does this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public abstract class Account { private String name. . . } public void withdrawal(float amt) { . . . . public FixedDepositAccount(String n. System. public void deposit(float amt) { . . All rights reserved. . We therefore declare a method called printAccount() as abstract. acct). .out. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public class FixedDepositAccount extends Account { . int acct) { super(n.println("Account name = " + getName()). . System. 43 . } public class SavingAccount Copyright c July 1999 Lee Chuk Munn. Abstract methods do not have a method body. } public abstract void printAccount(). . } public void printAccount() { System.Defining an Abstract Class 4.1. .println("Interest rate = " + getIneterest() + "%"). .1 cannot implement the printing at Account level. System. float amt) { . } } We declare the Account class as abstract by denoting it with abstract keyword in line 1. .out. In line 7.out. } public void transfer(Account from.

the Walkman has other buttons such as forward. acct). The “Play” button is therefore an interface between you and the Walkman’s internal machinery. backward. stop. A Walkman has a play button. 4.Interface 4. System. Besides the play button. Any cassette player with any one of these functions missing would deemed incomplete.out.println("Account name = " + getName()).out.2 17 18 19 20 21 22 23 24 25 extends Account { public SavingAccount(String n. When you implement an abstract method you drop the abstract keyword. 44 . All rights reserved.2 Interface What is an interface? It is a point where two entities meet. When you purchase a cassette player.println("Current balance = $" + getBalance()). you would expect these buttons (functions) to be present. etc. } public void printAcount() { System. the Walkman will play whatever tapes happens to be in it. Let’s consider a Walkman. } } Lines 7 and 21 implement the abstract method printAccount(). int acct) { super(n. These buttons constitute a cassette player’s interface. User I N T E R F A C E Provider Figure 4. We know that when we press it.1: Concept of an interface The Walkman example highlights the following point: Copyright c July 1999 Lee Chuk Munn.

To implement an interface. We cannot hardcode this calculation into Account. . To implement an interface we use the interface keyword. . 45 . These methods are very much like abstract methods in that they have no implementation. not the implementation. The syntax is as follows: public class <class_name> implements <interface_0>[.. Figure 4. • An interface guarantees all functions are complete.. All rights reserved. Your focus is on the interface..2 Implementing an Interface Classes can implement any number of interface. An interface has the following syntax: public interface <interface_name> [ extends <interface_1>. • The interface hides the implementation from the user.2.Implementing an Interface 4.1 Defining an Interface In Java. classes use the keyword implements in the class declaration. This interface has one single method called calculate() which performs interest calculations.2. what services it provides. Copyright c July 1999 Lee Chuk Munn. . . .] { . One is the provider. 4. A class that implements an interface must provide implementation for all its methods and methods in its super interface. We can use an interface to overcome this problem. } We will now add interest calculation to Account. <method_2>.2 • There are two sides in every interface. <interface_1>. We are well aware that interest rate fluctuates and the formula for calculating interest rates changes. 4. Define an interface call Interest.] { <method_1>. } Optionally an interface can inherit any number of super interfaces via the use of extends keyword. This is how we do it: 1. The other is the user. .1 illustrates the concept of an interface. otherwise we need to recompile everytime the interest calculation changes. . an interface is a set of methods under a name..2.

java” just like a class. . int no) { name = n. } } public class TightRate implements Interest { public float calculate(float amt) { return (amt * 0. . balance = 100F.01F). acctNo = no. public Account(String n. In our Interest example. • For 1 interface.Implementing an Interface 4. private Interest interest. . there are two implementations. You have to save this interface in a file called “Interest. 1 2 3 4 5 6 7 8 9 10 11 12 13 public class GenerousRate implements Interest { public float calculate(float amt) { return (amt * 0. } } Notice the way the Interest interface is defined and implemented: • Interface and its implementation are totally separate.2. We now turn our attention to Account. The Interest looks like this: 1 2 3 public interface Interest { public float calculate(float amt). } calculate() takes in the amount of money that you want to calculate the interest on and returs the interest on the input amount.2 2. multiple implementations are possible. Copyright c July 1999 Lee Chuk Munn. 46 . interest = null. Call calculate() when we want to calculate interest. Add a method in Account that accepts an Interest interface.5F). All rights reserved. The listing is as follows: 1 2 3 4 5 6 7 8 9 10 public abstract class Account { private String name. Lets implement two interest which we will call GenerousRate and TightRate. overdraft = false.

12345). line 16 to 21. 47 .1 list of their differences.println("generous = " + fred. .calculate(getBalance())).setInterestCalculation(new TightRate()). All rights reserved. Account will check if an interest calculation has been set. Notice that we use interest to hold an Interest interface. If it has then we call the calculate() method.out. } public float calculateInterest() { if (interest != null) return(interest.Differences between Abstract Class and Interface 4.setInterestCalculation(new GenerousRate()). System. fred. Copyright c July 1999 Lee Chuk Munn. We define a method to set interest calculation. else return(0F). } Comments on the above code: line 13 to 15. at the point time of invocation.3 Differences between Abstract Class and Interface Although abstract classes and interface provide similar features.out.3 11 12 13 14 15 16 17 18 19 20 21 22 23 } public abstract void printAccount().calculateInterest()). Let’s look at somemore code to see how all these works: 1 2 3 4 5 SavingAccount fred = new SavingAccont("Fred". otherwise we return 0. 4.calculateInterest()). public void setInterestCalculation(Interest i) { interest = i. Table 4. } . The entire key to interface hinges on this: we reveal an object’s interface (methods therein) without relying on any one class (line 18 ). When we invoke this method. . The JVM will lookup the actual implementation during runtime viz. the are in fact quite different.println("tight = " + fred. System. fred.

Differences between Abstract Class and Interface 4. Static in the sense that it is compiled into a class. All rights reserved. You must implement all the methods in it. Can only subclass 1 abstract class. You can implement more than 1 interface. You are allowed to selectively override any abstract methods. 48 . Interface You implements and interface. Dynamic because you can change an interface’s implementation at runtime.1: Differences between abstract class and interface Copyright c July 1999 Lee Chuk Munn.3 Abstract Class You extends an abstract class. Table 4.

Components is the base class of all AWT widgets (eg. A disabled component is greyed out and is not usable. Component provides the following methods which are common across all components: public void paint(Graphics g) Called when the Container needs to update the GUI. Graphics is an abstraction of the screen. 49 . a disabled Button cannot be pressed. 5. public void setForeground(Color c) Sets the foreground color of a component. Button. public void setEnabled(boolean b) Enable or disable a component.1 Component and Container The basic GUI building blocks in AWT are Components and Containers. the JDK allows you to develop GUI front ends by using the Abstract Windowing Toolkit or more commonly know as the AWT. public void repaint() Force an update of the component.). public void setBackground(Color c) Sets the background color of a component. As the base class.Chapter 5 Building GUIs with AWT The graphical user interface (refer to GUI henceforth) is an important part of the modern day application. eg. List. Control will be passed to this method for drawing. We will use the word component to refer to AWT widgets collectively and Component to refer specifically to the class. call this method when you need to the component to be redrawn. We will look at Container and Graphics shortly. Like most programming libraries. etc. Choice.

lang. Here is the catch: since Containers are themselves subsclass of Component.setBackground(Color. All rights reserved.Component and Container 5. We will look at manipulating fonts in section 5. frame. frame. The above is not an exhaustive list of all methods. we can build very complex GUIs. Lets take a bird’s eyeview of building a simple GUI with Components and Containers before we proceed further. Component c) Adds a component to a name location in Container. public Component add(String name.yellow).2.setBackground(Color. 100). you add components in to Containers. button. } } Copyright c July 1999 Lee Chuk Munn.white). The Container class. frame. public void setLayout(LayoutManager mgr) Sets a LayoutManager to the Container. button. Frame frame = new Frame("A Frame").setSize(200. frame.setVisible(true).setForeground(Color.add(button). We will look at LayoutManager in section 5.6. please consult the the Component API documentation.1. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import java.1 public void setFont(Font f) Sets the font for this component. you can add Containers to Containers! Using this technique.awt. The following are important methods in Container class: public Component add(Component c) Adds a component to a Container.red). To built a GUI. } public static void main(String[] args) { AFrame aFrame = new AFrame(). as the name implies acts as a container for components. import java.*.setLayout(new FlowLayout()). 50 . public void requestFocus() Set the mouse focus to this component. public class AFrame { public AFrame() { Button button = new Button("Press Me!"). frame.*.

51 . GridLayout and BorderLayout.1. line 8. line 12.awt package manually otherwise your program will not compile.2 LayoutManager The layout of components within a Container is done by LayoutManager. We will examine only the following 3: FlowLayout. line 9. line 13. Before you add any components to a Container you need to set the layout or arrangement of the Container using setLayout() method. how components in frame will be arranged.java An explanation of AFrame. we display the frame by setting its visible property to true. The LayoutManager controls all aspect of a component in the Container: its placement. 5. We create an instance of Frame which is a subclass of Container. line 5.java is as follows: line 2. The width and height is 200 by 100 pixel respectively. Set the layout or arrangement viz. The JDK comes with 5 LayoutManagers. The LayoutManager controls the placement of components according to its the LayoutManager’s layout policy. you have to import java. Add the button to the frame for display. All rights reserved. when all the setup is completed. etc.LayoutManager 5. line 6 and 7. Sets button’s foreground and background color. Finally. Sets the frame’s size for display. Recall Button is a subclass of Component.1: GUI produced by AFrame.2. orientation.lang package which is imported by default. We create an instance of Button. Unlike java.1 The GUI produced by the previous code snippet is shown in figure 5. line 11. size. Copyright c July 1999 Lee Chuk Munn. Figure 5.

FlowLayout will try to fit as many components on a line as possible before moving them to the next.*. Figure 5.2. FlowLayout will rearranges the components according to the new Container’s size.add(new Button("Two")).setLayout(new FlowLayout()).2. When you resize a Container.*. 52 .lang. } public static void main(String[] args) { FlowLayoutEx ex = new FlowLayoutEx(). frame.add(new Button("Three")).awt. public class FlowLayoutEx { public FlowLayoutEx() { Frame frame = new Frame("FlowLayout").2. frame.2 5. frame. frame. } } Notice that in line 6. we set the FlowLayout to be the layout of the frame. frame.2: Container managed by FlowLayout Copyright c July 1999 Lee Chuk Munn. frame. you will see the frame as shown in figure 5. The following code adds 3 Buttons to a FlowLayout managed Container. All rights reserved.FlowLayout 5. from left to right and from top to bottom. All subsequent add (line 7 to 9 ) will be under FlowLayout’s control. import java. the buttons will adjust to accomodate the new size.setSize(200. When the frame is resized. When you run FlowLayoutEx program. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import java.setVisible(true).1 FlowLayout FlowLayout arranges components in a Container like sentences in a page. 100).add(new Button("One")).

frame. import java.awt. "C". "F" }.3 5.BorderLayout 5. "B". frame.2 GridLayout The GridLayout devides the Container into a specificed number of rows and columns.2. very much like a matrix. you need to specify the region or your component will not show up when you display the container. Components in the grid are arranged from left to right and from top to bottom. } } Figure 5.pack().3: Container managed by GridLayout Do not over or under add() a GridLayout managed container. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import java. otherwise the layout of your component will be unpredictable. “south”. The following code adds 5 buttons to the 5 region in BorderLayout. } public static void main(String[] args) { GridLayoutEx ex = new GridLayoutEx().length. All rights reserved.lang. The following code snippet creates a 3 rows by 2 columns grid.*. Copyright c July 1999 Lee Chuk Munn.3 BorderLayout BorderLayout divides a container into 5 region. They are “north”. public GridLayoutEx() { Frame frame = new Frame("GridLayout"). 2)). 53 . public class GridLayoutEx { private String[] label = {"A".2. for (int i = 0.2. 5.setVisible(true).add(new Button(label[i])). "E". When you add a component to a BorderLayout managed container. i++) frame. "D".*. “west” and “center”.setLayout(new GridLayout(3. i < label. “east”. frame. The size of each cell is the size of the largest component in the grid.

NORTH).add(new Button("South"). frame.add(new Button("East"). } public static void main(String[] args) { BorderLayoutEx ex = new BorderLayoutEx(). BorderLayout.lang. 200).setLayout(new BorderLayout()).SOUTH). 54 . BorderLayout.4: Container managed by BorderLayout Copyright c July 1999 Lee Chuk Munn. The result of BorderLayoutEx is shown in figure 5.setVisible(true).4. import java.EAST). The first parameter of add() is the component itself.add(new Button("North").add(new Button("Center"). BorderLayout. All rights reserved.setSize(200. } } Note lines 7 to 11.*. frame.CENTER). in this case a Button while the second is the position. frame.*. BorderLayout. frame.WEST). frame. Figure 5. BorderLayout. frame.3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import java. frame.awt.BorderLayout 5. we specify the region the component is to be added.add(new Button("West"). frame. public class BorderLayoutEx { public BorderLayoutEx() { Frame frame = new Frame("BorderLayout").

4.awt. ScrollPane — These are scrollable Panels. Frame — This is a top level application window.1 Using Panel in Complex GUIs Panels allow us to create very sophisticated GUIs. Dialog — These are temporary frames for prompting users and for displaying messages.5: A Java calculator Although the layout of the caluclator does not resemble any of those that we have seen. 2. They must be added to containers. Panel — Panels are your basic component laying containers. We will examine Panel and Frame in greater detail in the following section.5. 3.Using Panel in Complex GUIs 5. they provide layout control as we will shortly see.awt. Although Panels themselves are not part of the visible GUI.*. The JDK java. The code to create the calculator is show below: 1 2 3 4 import java. They can be added to Frames. package have different containers. they are 1. Figure 5.lang. All rights reserved. import java. Dialog. public class Calculator extends Frame { Copyright c July 1999 Lee Chuk Munn.3 Container Components cannot exist in limbo. ScrollPane and Panel. 5. 55 . it is in fact done by cleverly combining 2 layouts and 2 Panels.*. Consider the calculator in figure 5. ScrollPane and Dialog are variations of Panel and Frame and will be left as an exercise for the reader.3.1 5.3.

add(base. Panel numberPad = new Panel(). "4".add(new Button(label[i])). 10). "6". for (int i = 0. base.Frame 5. This is our calculator’s keypad. 56 .setBackground(Color. 4)). base. "7". 5. calc. "=". BorderLayout. You can add as much layers of Panel as you like to create the desire layout. "0". line 19. Add the numberPad to the “center” of base. BorderLayout. We add the display which we created in line 16 to the “north” of base line 20. The default layout of Panel is FlowLayout. Study the GUI and decide on the most optimal way to construct the GUI.setLayout(new GridLayout(4.2 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 private String[] label = {"1".setForeground(Color. "-".add(display.2 Frame All components must be added to a Frame to be visible. "/"}. i++) numberPad. Creates a Panel call numberPad. unlike Panel a Frame cannot be added to another Frame Copyright c July 1999 Lee Chuk Munn.NORTH). "9".CENTER). public Calculator() { super("Calculator"). "*".3. numberPad. base.setLayout(new BorderLayout()). A good habit to acquire when developing GUI using AWT is to first draw the GUI.length. We instantiated another Panel and set this to BorderLayout. line 14 and 15.setVisible(true). "3". pack(). "8". i < label. display. } } The key to the calculator application lies in line 20. Frames are standalone componets. Panel base = new Panel(). } public static void main(String[] args) { Calculator calc = new Calculator().black). display. All rights reserved.3. "C".add(numberPad. "2".green). BorderLayout. "+". line 10 to 13.CENTER). TextField display = new TextField("0". "5".

Other useful methods include: public void setTitle(String title) Sets or changes the Frame’s title. 5. it is always good to call this method. The following code creates a button with the label “Press Me!”. All rights reserved. You can do this by either using the setSize() or pack() method. Set the size of the Frame. This is equivalent to calling setVisible() with false.4.4 5.1 AWT Components Button To create a button we us the Button class. public Frame(String title) Creates an instance of a Frame with the specified title.8. We will look at menus and menu bars in section 5.4. If you forgot to set the window size. public void setResizable(boolean b) Allows the Frame to be resized. Make the Frame visible. pack() tells the Frame to use the smallest possible size to display its components. dispose() frees all resources associated with the Frame instance.1 even though it is a subclass of Container. public void setMenuBar(MenuBar mb) Sets a menu bar to the Frame. public void dispose() Before discarding a Frame instance. To display a Frame you have to perform the following steps: 1. public void hide() Hides the Frame. The class Frame has the following 2 constructors: public Frame() Creates an instance of a Frame without a title. 2. Copyright c July 1999 Lee Chuk Munn. The Button allows label but no images to be display on its face. 57 . the Frame will not be visible even though you callsetVisible(). visible. This is done by calling setVisible() with true. Frames by default are BorderLayout managed.Button 5.

Copyright c July 1999 Lee Chuk Munn. true.setLayout(new GridLayout(1. panel. The default state is false. cbg)). cbg)).add(new Checkbox("Reebok")). cbg)). 58 . panel. A Checkbox can specify a CheckboxGroup object when instantiated. boolean state) Instantiate a Checkbox setting the state of the newly created Checkbox to state. panel. 3)). Panel panel = new Panel().4. panel. panel.4.4 1 Button button = new Button("Press Me!").add(new Checkbox("Nike".add(new Checkbox("Reebok". false. When a Checkbox within a CheckboxGroup is selected. All rights reserved.3 CheckboxGroup Checkboxes may optionally be part of a CheckboxGroup which simulates “radio button” behaviour. panel. the CheckboxGroup ensures that the previously selected Checkbox becomes unselected.CheckboxGroup 5.add(new Checkbox("Adidas")). 5. 3)). Figure 5. 5.6 is created by the following code: 1 2 3 4 5 Panel panel = new Panel(). panel. The previous Checkbox example can be converted to a CheckboxGroup as follows: 1 2 3 4 5 6 CheckboxGroup cbg = new CheckboxGroup().6: A Checkbox component Checkbox has the following 2 constructors: public void Checkbox(String label) Instantiate a Checkbox with label.add(new Checkbox("Nike")).2 Checkbox Checkbox provides a simple two state button. panel.setLayout(new GridLayout(1.add(new Checkbox("Adidas".4. Figure 5. false. public void Checkbox(String label.

list. public void remove(String label) Removes an item. Figure 5. All rights reserved. public void select(String str) Programatically selects an item from a Choice.4.7: A Choice component The add() method adds an item item with the specified label to Choice. 1 2 3 4 List list = new List(4. The List is scrollable if necessary. The List constructor takes two optional arguments that specifies the number of visible rows in the list window and whether multiple selection in the List is possible.4 Choice This class represents a drop down list. Other methods in Choice includes: public String getSelectedItem() Returns the label of the selected item.add("Nike").4. choice.add("Reebok").add("Nike"). choice.5 List A List component is used to display a list of strings. choice. list. 59 .4.add("Reebok").List 5.add("Adidas"). true). The following illustrates its use: 1 2 3 4 Choice choice = new Choice(). Copyright c July 1999 Lee Chuk Munn.add("Adidas").7. public int getItemCount() Returns the number of items in a Choice. 5.5 5. list. A Choice is shown in figure 5.

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.6 Label Label as the name implies are a single line of text used for labelling components.4.8: A List component Other userful methods in this class are: public void add(String item) Adds an item to the List. Copyright c July 1999 Lee Chuk Munn.Label 5. public int getItemCount() Returns the number of items in the List. 60 . All rights reserved. public void setMultipleMode(boolean b) Enable/disable multiple selection mode for the List. public String[] getSelectedItems() Returns all selected items if multiple selection is enabled. public void select(int index) Programatically selects an item at position index. 5.8. Figure 5.7 creates a List with 4 visible items and allows multiple selection as shown in figure 5. A label is created as follows: 1 Label label = new Label("Name:"). public void remove(String item) Removes an item from the List. public String getSelectedItem() Returns the selected item.4.

61 . public void setCaretPosition(int index) Sets the caret at the specified position.4.7 TextField These are single editable line of text.add(new Label("Name: ")). Figure 5.4.9. You can also use the above mentioned TextField methods with TextArea. Copyright c July 1999 Lee Chuk Munn. This is normally used for password entry. panel.8 TextArea This class displays and allows you to edit multi line text. All rights reserved. insertText() and replaceText() provides various techniques for specifying text to appear in the TextArea. The code produces the figure 5.4. The following code creates a TextArea that is 40 columns wide and 5 rows high.TextArea 5. public void setEditable(boolean b) A bit like setEnabled() in Component.8 5. This method makes the TextField either editable or uneditable. TextField is normally used in forms type applications where the user is required to fill in their personal details.9: A TextField component Other interesting TextField methods are: public void selectAll() Highlights the text in the TextField. 5. public void setText(String msg) Set the text msg in the TextField. The methods appendText(). panel. public void setEchoChar(char c) Displays the character c in the TextField for any characted typed into the TextField. The following creates an entry to solicit a user’s name: 1 2 3 Panel panel = new Panel().add(new TextField(30)).

5. update() and repaint(). 5. In this case. All rights reserved.1 paint(Graphics) Method The paint() method handles most of the painting of the components. Forced — When a program wants to update the screen eg.5. 40). 5. To customize a component. the JVM will call paint() directly. an animated button needs to draw the next image. we override this paint() method. 5.6 in page 63. The program can call repaint() to force a redraw. A question arises: what if we want to customize components? How do we add “wall paper” to a Panel or an image to a Button? To be able to do these and more. The previously mentioned 3 methods are part of Component. The following sequence of method cals occurs: repaint() −→ update() −→ paint() Copyright c July 1999 Lee Chuk Munn.5. these components draw themselves on the screen. the JVM will call the paint() method of each component in a Frame.2 repaint() Method Sometimes we want to update a component on the window or the entire window all together. 62 . We will look at Graphics in section 5. Recall that Component is the superclass of all components (widgets). Horizontal and vertical scrollbars will automatically appear when required. we must first understand the AWT paint cycle.repaint() Method 5. We invoke repaint() which schedules a cal to update(). The components will redraw themselves again when either one of the following 2 events occurs: Exposure — This happens when we resize a frame.3 1 TextArea textArea = new TextArea(5. The key to customization lies in the following methods: paint().5 The AWT Paint Cycle We have seen how most of the components behave. Whatever we “draw” on Graphics will appear on the screen. an overlapped portion of the frame is exposed or whenever the JVM thinks that the component requires to redraw itself on the screen to update its appearance. When a component is first displayed. The signature for paint() is as follows: public void paint(Graphics g) The Graphics parameter is an abstract representation of the screen.

Copyright c July 1999 Lee Chuk Munn. it is quite inefficient to redraw the entire screen. public void drawRect(int x. int width. public void drawString(String str. ovals. 63 .5. public void setColor(Color c) Sets the color for the drawing pen. the default behaviour is sufficient. For most application. The following is a partial list of methods. int y_2) Draws a line from (x_1.6 Graphics The Graphics is an abstraction of the screen. We will not look into this subject any further. int y_1. int x. What you draw on Graphics will appear on the screen.6. etc. y_1) to (x_2.Graphics 5.1 5. y_2).3 update(Graphics) Method update() is an intermediate method call when we call force a redraw but is never involved on an exposure update. 5. int x_2. Note that (x. The reason is twofold: firstly. int y. Clears the component by filling the component with its background color. Calls paint() with Graphics that it receives. and secondly excessive clearing and redrawing will cause the screen to flicker. int y. int height) Draws an oval. public void drawOval(int x. 2. int height) Draws a rectangle. developing arcade style games or anything along those lines you might want to override update(). y) refers to the lower left corner of the str instead of the the normal upper left corner. The default behaviour of update() is as follows: 1. int width. All rights reserved. The Graphics class provides some highlevel drawing methods like drawing lines. public void drawLine(int x_1. Why is this so? The reason is to allow more control over the painting process. public void setFont(Font f) Sets the font to be used. int y) Draws str on (x. y). But if you are doing animation.

int size) name This is the name of the font. BOLD or ITALIC or the sum of BOLD and ITALIC. you can also use the fonts installed on the native operating system. The font style is bold and italicised. 1 2 Toolkit toolkit = Toolkit. g. The following code snippet gets a list of installed fonts from the operating system which you can then use. 64 .1 default font or query the operation system for the required font. 100).10: An example of using font Copyright c July 1999 Lee Chuk Munn.Using Font 5. SansSerif. The following creates a ”Monospaced”. The output is shown in figure 5. Besides the JDK 1. String[] installedFonts = toolkit. 20 point font.setFont(new Font("Monospaced".getDefaultToolkit().getFontList(). } Figure 5.BOLD + Font. 10. int style. 1 2 3 4 public void paint(Graphics g) { g. Monospaced. style The style can be one of the following: PLAIN. Font. All rights reserved.7 5.drawString("Hello World!". You can either use the JDK 1. Dialog and DialogInput.ITALIC.6. 20)). size The size of the font.1 Using Font JDK 1.1 supports the following font types: Serif.10.1 include fonts. The Font class has the following constructor: public Font(String name.

Customizing Components 5.awt package.7 5. i < count. } public void paint(Graphics g) { Dimension size = getSize().7 Customizing Components We have seen all the required pieces of Java techology to allows us to customize components. i++) g. Figure 5.black). i*10.drawLine(0.red). count = size.blue). for (int i = 1. We will create a customize Panel by giving it a wallpaper of squares as shown in figure 5.11: PrettyPanel with a button The code to create PrettyPanel is as follows: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import java. size.setColor(Color. for (int i = 1. i*10). size. Lets put these different pieces together and see how it all fits together. i*10.height). g.width.drawLine(i*10. int count = size.setColor(Color. Copyright c July 1999 Lee Chuk Munn. Do not forget to import the java.*. 0. g.awt. 65 . public class PrettyPanel extends Panel { public PrettyPanel() { setBackground(Color.*. } } The explanation is as follows: line 2.lang.width/10. i < count. i++) g.11. import java.height/10. All rights reserved.

The former becomes a submenu of the latter. These are the normal pulldown menus that appear on top of a frame. you need to perform the following steps: 1.2 line 5.add(new Button("Press Me!")). 4. The following code adds a MenuBar to a Frame: 1 2 3 Frame frame = new Frame("Menu"). We draw red vertical lines. To add a menu to a Frame. These will appear as labels on the MenuBar. line 10 to 13.MenuBar 5. Copyright c July 1999 Lee Chuk Munn.8 Adding Menus to Frame You can set menus to frame. line 14 to 17. Add MenuItem and/or CheckboxMenuItem to Menu. Graphics represents the display area of PrettyPanel and getSize() gives us this area. 10 pixel apart. Add a MenuBar to a Frame by calling setMenuBar() method. 66 . All rights reserved. We draw blue horizonal lines. Since constructors are not inherited. You can optionally add a Menu within a Menu. 5. Just for fun. Remember. we provide a constructor. consider the following code: 1 2 PrettyPanel pretty = new PrettyPanel(). line 6. 10 pixel apart. We override the paint() method to provide our own drawing.8. 3. 2.8. Get the size of the Panel. line 8. Only 1 MenuBar instance can be added to a Frame. 5. frame. MenuBar menuBar = new MenuBar().1 MenuBar A MenuBar is required before you can create menus. We need to know the size so that we can draw the appropriate number of lines. pretty. Add Menus to MenuBar. Using PrettyPanel is like using your regular Panel.setMenuBar(menuBar). we set the default background to black. line line 9.

3 MenuItem and CheckboxMenuItem MenuItem and CheckboxMenuItem are the leaf node in Menu.add(new MenuItem("Save")). fileMenu. . “Save As. fileMenu. MenuItem and CheckboxMenuItem must be added to Menu.")).setHelpMenu(aboutMenu). At the name implies.8.2 Menu Menus are labels that are displayed on the MenuBar. “Open” and “Exit” to “File” menu. fileMenu. 1 2 3 4 5 6 Menu fileMenu = new Menu("File").12: An example of a Frame with a MenuBar 5. ”.add(new MenuItem("Exit")). menuBar. menuBar. We now add “Save”. “File” and “Edit” to a MenuBar. Menu aboutMenu = new Menu("About"). We will now add 2 menus. Copyright c July 1999 Lee Chuk Munn.add(new MenuItem("Save As. All rights reserved. Again.8. Menu editMenu = new Menu("Edit").addSeparator(). menuBar. see figure 5.MenuItem and CheckboxMenuItem 5. a help menu provides help.add(new MenuItem("Open")). information and the usual about dialog box. fileMenu. the code continues from the previous example. Typically. You can only set one help menu per MenuBar instance.add(editMenu).. Line 6 adds a help menu to the MenuBar. . 67 .add(fileMenu). 1 2 3 4 5 fileMenu. Figure 5.9 5.. The addSeparator() on line 4 adds a line to the menu. The following code is a continuation of the example form the previous section. MenuItem and CheckboxMenuItem would represent the actual functions that we wish to provide to the user.13.

68 . For that we need to understand events which we will examine in the chapter 7.AWT Events 5. But our GUI is still deviod of life.13: A menu with MenuItems 5. The GUI does not know how to respond to mouse clicks.9 AWT Events We have seen how easy it is to use AWT components to create GUI. Copyright c July 1999 Lee Chuk Munn. All rights reserved.9 Figure 5.

1 Member Class Member class are particularly useful for defining utility or helper classes. These helper class are not very closely related to the main class in the sense that they cannot access the main class’ internal methods and members.Chapter 6 Inner Class The JDK 1. Prior to JDK 1. we personally feel that member classes and anonymous classes are the most useful. Member class can access containing class’ methods and members. Member classes overcomes these difficulties. You have to resort to parameter passing. even private denoted ones. Of the 4 types of inner classes mentioned above. typically within a method. They are defined and used only once. Anonymous class These are nameless classes. There are 4 categories of inner classes: Nested top level classes and interfaces Classes and interfaces defined with the static keyword. one of these is inner classes. Hence they are only visible within a block. When using member class. Local class Local classes are like member classes except that they are defined within a block. 6. The remainding 2 inner classes are variations of member and anonymous class.1 introduces a number of new features to the Java language. Inner classes are simply classes within classes. you have to remember the following: 69 .1. Cannot access containing class’ methods and members. Member class Member classes are classes without the static keyword. helper classes must be defined as a separate “top level” class. This can sometimes be very crumblesome. As such we will be focusing our attention on them.

} . it will install a default interest calculation method. } } public Account(String n. } public float calculateInterest() { return (interest. including private methods and members. • A member class can access its methods and members as well as those of its containing class. . } The explanation for the above code is as follows: line 6 to 11.Member Class 6.calculate(getBalance())). public void setInterestCalculation(Interest i) { interest = i. Our inner class is called DefaultRate and it implements the Interest interface. .1F). . All rights reserved. We will demonstrate the use of member class by adding the following features to the Account on page 43 so the it performs the following: • When a subclass of Account is instantiated. • A user can install its own interest rate calculation method via the setInterestCalculation() method. . Notice that declaring a member class is just like defining a regular top level class. This is the member class. private float balance. } . The new Account class looks like this: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public abstract class Account { private String name. 70 Copyright c July 1999 Lee Chuk Munn.1 • An instance of a member class must always be associated with an instance of its containing class. . int no) { interest = new DefaultRate(). . . . public class DefaultRate implements Interest { public float calculate(float amt) { return (balance * 0. private Interest interest.

If we follow the usual rule and rewrite the above to this return (this. Does this apply for inner classes as well? Lets take a look again at line 9 of Account which is reproduced below: return (balance * 0. The syntax is <class_name>.1F). 71 . • You are defining a class and this class is of no use to any other classes except one.1 Referencing Containing Class’ Members Recall that all instance methods and members are implicitly prefixed by a this.this. we directly access balance to calculate the interest ignoring amt. public class Inner { public String msg = "inner".balance * 0. To access the containing class’ member.class which is the inner class.1F). When we instantiate Account we set the interest member with an instance of DefaultRate. This is because “this” refers to the current instance and the current instance which is an instance of DefaultRate does not contain a member called balance. So using this would be wrong.1 line 9. In addition to the Account. you will also find the class Account$DefaultRate. When do we use member class? We offer the following guidelines: • When you require a helper or a utility class. balance is actually the containing class’ member. public class InnerInner { Copyright c July 1999 Lee Chuk Munn.1. • Two classes have interwind relationship. line 13.balance * 0.class.Referencing Containing Class’ Members 6. Compiling Account will now produce not 1 but 2 classes. we would get an error message.this where <class_name> is the name of the containing class. 6. we use a variation of the this. All rights reserved.1. The following class further illustrates this concept: 1 2 3 4 5 public class Outer { public String msg = "outer". Line 9 would look like the following when written in its entire form: return (Account. Since member class can access its containing class’ members.1F).

Creates an instance of InnerInner within inner.new InnerInner() and not inner. Outer. line 1.new Inner().this.InnerInner innerInner = new inner.new InnerInner(). public void print() { System.prinln("msg = " + InnerInner.Inner inner = new outer.out. Creates an instance of Inner within outer.msg).prinln("msg = " + Inner. System.this. System. .out.this.new.2 Instantiating Member Classes Instantiating member classes presents a few problems. line 3.Inner.msg). Creates an instance of Outer first.Inner. So we have to instantiate the containing class first before creating the member class.InnerInner() 72 Copyright c July 1999 Lee Chuk Munn. The syntax for instantiating a member class is <containing_instance>. System.prinln("msg = " + Outer.new Outer.2 6 7 8 9 10 11 12 13 14 15 public String msg = "innerinner". innerInner.print(). we name the class to be created relative to the instance that is going to contain it like so inner.out. Note the following about instantiating member classes.Instantiating Member Classes 6.msg). Remember that a member class must always be associated with its containing instance. In the new. line 2. The following code snippet creates an instance of all member class in Outer: 1 2 3 4 Outer outer = new Outer().1.prinln("msg = " + msg). All rights reserved. Outer. } } } } The output will be msg msg msg msg = = = = innerinner innerinner inner outer 6.out.

} }.. .]) { <class_body> } or new <interface_name>() { <interface_body> } When you are creating an anonymous class using an interface. int no) { . . . private Interest interest.. . The anonymous class syntax combines class definition with instantiation. Refer to the following section. Unlike member class where you have to define and instantiate the class to be used. Let’s take a look at an example of anonymous class before discussing in greater detail. 73 . Anonymous classes can be defined in 2 ways: new <class_name>([<type> <param_1> . } The lines between 8 and 12 inclusive defines an anonymous class. All rights reserved. interest = new Interest() { public float calculate(float amt) { return (balance * 0. . anonymous classes combine these 2 steps into 1.Anonymous Class 6. public Account(String n. private float balance.1F). Anonymous classes cannot have constructors. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public abstract class Account { private String name. remember you are implementing the interface so you must implement all the interface’s method. We rewrite (again!) Account using anonymous class instead of member class as in page 70. . When do you use anonymous class? You would use them if Copyright c July 1999 Lee Chuk Munn.2 Anonymous Class Anonymous classses are classes without names.2 6. . However if you really need to initialize the class you can resort to “instance initializers”. } .

1F. 0.MONTH)]. interest = new Interest() { private float monthlyRate[] = { 0.1F. 6.1F. .} } public float calculate(float amt) { return (balance * rate). 0.1 Instance Initializers Instance initializers are arbitrarily blocks of code in a class definition. } } } . 0.1F. { rate = monthlyRate[ (Calendar. • Only one instance of the class is needed.07F.get(Calendar. 0. 0.1F. . We add an instance initializer to the previous anonymous class example.Instance Initializers 6. . then they are executed in the order in which they appear. Copyright c July 1999 Lee Chuk Munn. The anonymous class calculates the interest rate to use based on the month. . 0. . 0. public Account(String n. 0. The instance initializer (lines 7 to 10 ) gets the appropriate interest rate according to the month when the anonymous class is instantiated. They are executed after the superclass’ constructor but before the class’ constructor.2. If a class has multiple instance initializers. private float rate.12F. All rights reserved.05F }. • The class is use immediately after being defined.2.1F.1F. int no) { . 0. 0. 74 . only the constructor is shown: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 .1 • A class has a very short body.1F.08F. 0. .getInstance()).

The way to tackle it would be to implement the said GUI using the model/view/controller (MVC for short) introduced in Smalltalk-80. We will begin this section by looking at the MVC architecture and how 75 . eg. Your front end has to be generic as lots of existing and new yet undevelop applications will be using it.1.Chapter 7 Handling AWT Events You are asked to develop a forms front end. It must be modular and allows on-the-fly customization. if any of the underlying information changes. one application uses the the HKID field as an index into a database to verify the input data while another runs an hash function to verify its correctness. much like the one shown in figure 7. Figure 7. If you were to write the code that handles each requirement. the form must be able to update itself.1: A typical GUI front end None of these requirements presents an insurmountable programming challange. it would add significant coding to your overall effort. More importantly.

Future enhancements and components written to the API can replace either the model.2: The model/view/controller architecture The MVC has the following benefits: • Encourages the application to be data (model) centered instead of user interface (view) centered. view or controller. 7. Figure 7.1.The Model 7.1 they influence the desgin of AWT. We will then move on to handling AWT events and eventually creating our very own custom events. 7. The model has no specific Copyright c July 1999 Lee Chuk Munn. • A well defined separation between components of a program. • The binding between the 3 components are dynamic and occurs at runtime. view and controller. Each component can be written separately. This can be a file. All rights reserved. 76 . a matrix stored in an array or records held a database.1 The MVC Architecture The MVC was designed to reduce the overall programming effort by delegating specific responsibilities to the model.1 The Model The model is an object that represents the data.2 illustrates the MVC architecture. • Each component has a well define set of API. View Controller View Model Controller View Controller Figure 7.1.

2 The View Views are the faces of the model. A view might sent out an event. Components sending the event. the model saves the data into a database. 7. Copyright c July 1999 Lee Chuk Munn. If the model changes. a pie chart. 7.2 knowledge of either its views or controllers. All rights reserved. 7. Listener and Event Objects The entire AWT is based on the delegate model. a HTML page.1. notifying the model that the user has changed portion of the data. Figure 7. for example. notifying the recipient that something interesting has happened.2 Events Events are messages sent from one object to another. the model is responsible for invoking the appropriate controller. 7.1.1. the components receiving the events are called event listeners.Identifying Source. Events are key to implementing MVC in Java. Events can be single or multicast. 77 .2. The model. Examples of views include the traditional window GUI. Capturing a Button pressed or a mouse clicked require us to register and capture the correct event. fires another event to the various controllers to validate the new data. When the controllers have completed their job. Validating date fields and checking the existance of records are just 2 examples of what you can do with controllers. introduced as part of the revamped AWT in JDK 1. etc. event sources and event objects. 7.2 Identifying Source. Event listeners must register themselves with event sources in order to receiving notifications. A record’s data can be represented by different views. If a particular piece of data requires validation for example. LED displays or your humble text.2.3 is a diagram of this interaction. is said to fire the event. The delegate model works as follows: an event source sends a notification to the listener and passing to the listener an event object. the event source.3 The Controller The controller provides a means of interacting with the model. The view is also responsible for representing the data in different forms: as a graph.1 The AWT Event Model The current AWT event model. on receiving the event. is called the delegate model. Listener and Event Objects 7.2. It is comprised of event listeners. the model is responsible for notifying its view.

3: Event source and listeners As it turns out. the delegate model follows a certain naming convention. The naming convention are as follows: Event source Event sources provides registration and deregistration for listeners. These are listeners for the XXX event. very much like the getter/setter method for encapsulating properties.2 Event Source Register event listener Event Listener Fire event Event Object Figure 7. 78 . Listener and Event Objects 7. Every method in the XXXListener interface will have this one and only object as parameter. Lets look at a concrete example: to capture a Button click. Using the above mentioned naming conventions. Event object An event object has the following name XXXEvent. we must capture the “action” event. 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 interface. All rights reserved. we know the following: • Action event sources are those objects which have the following methods: Copyright c July 1999 Lee Chuk Munn.2.Identifying Source.

These methods are called event handling methods. 79 .Event Listener Interface 7.3 Event Listener Interface The event listener interface is an interface that contains methods denoting specific events. The table 7. Component Button List MenuItem TextField Scrollbar Component Listener Interface ActionListener Listener Methods public void actionPerformed() Event Class ActionEvent AdjustmentListener ComponentListener Container Component Checkbox CheckboxMenuItem Choice List Component ContainerListener FocusListener ItemListener public public public public public public public public public public void void void void void void void void void void adjustmentValueChanged() componentHidden() componentMoved() componentResized() componentShown() componentAdded() componentRemoved() focusGained() focusLost() itemStateChanged() AdjustmentEvent ComponentEvent ContainerEvent FocusEvent ItemEvent KeyListener Component MouseListener Component TextComponent Window MouseMotionListener TextListener WindowListener public public public public public public public public public public public public public public public public public public void void void void void void void void void void void void void void void void void void keyPressed() keyReleased() keyTyped() mouseClicked() mouseEntered() mouseExited() mousePressed() mouseReleased() mouseDragged() mouseMoved() textValueChanged() windowActivated() windowClosed() windowClosing() windowDeactivated() windowDeiconified() windowIconified() windowOpened() KeyEvent MouseEvent MouseEvent TextEvent WindowEvent Table 7. All rights reserved.2.3 public void addActionListener(ActionListener l) public void removeActionListener(ActionListener l) • Action event listeners are those objects which implements the ActionListener interface.2. • ActionEvent is the event object passed from the event source to the event listener. When Copyright c July 1999 Lee Chuk Munn.1 show a list of all AWT events.1: AWT event list 7.

Notifications are made by invoking specific methods in the MouseListener interface. 80 . the event source will call mouseClicked() method. The rollover button will do the following: when the mouse pointer moves over the surface of the button. the appropriate event method is invoked. Related event handling methods are grouped into a single interface eg. Multiple listeners can register with a source to receive event notifications.awt. the MouseEvent object would contain information like the number of mouse clicks and the position of the mouse pointer when the event occur.6 an event occurs. 7. All rights reserved.5 Event Objects Event objects encapsulates all information pertaining to a specific event.2. the button’s background will turn red while the button’s label will be black. Event objects are passed from the source to the listener via the event handling methods. then getSource() will return a reference to fredButton. As noted earlier. So if a reference fredButton fires a ActionEvent. In the case of a mouse event. Copyright c July 1999 Lee Chuk Munn. We will use AWT event to implement just such a button.2.A Button Example 7. All AWT’s event objects are subclass of AWTEvent in the java. event sources provides events registration and deregistration methods.2. The getSource() method which all XXXevent inherits returns the event source object. the button’s color is reversed.2.event package.6 A Button Example The AWT does not have a rollover button. 7. When the mouse pointer leaves the button. The RolloverButton is a subclass of Button. for example when a mouse button is pressed. The steps are as follows: 1. the MouseListener interface 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 implement this interface. A listener calls the appropriate addXXXListener() to register itself as a listener and removeXXXListener() to stop receiving events notification. 7.4 Event Source Event sources are objects that fire events.

The listener must implement the MouseListener.awt. public class RolloverButton extends Button implements MouseListener { public RolloverButton(String label) { super(label). } public void mouseClicked(MouseEvent mEvt) { } public void mousePressed(MouseEvent mEvt) { } public void mouseReleased(MouseEvent mEvt) { } } The explanation for the RolloverButton class is as follows: line 3. We must implement MouseListner interface to capture mouse events. line 5.awt.red). Here. Notice that we are adding ourself as a listener viz. All rights reserved. Our specification is that when the mouse pointer leaves the button. 4. 81 . 3.black).awt. Perform the necessary color change in the event handler methods. we fake a mouseExited() event to set the initial button behaviour.red).black). addMouseListener(this). line 10. line 9. We reuse Button class since RolloverButton is essentially a Button.6 2. setForeground(Color.*.*.event.*. Copyright c July 1999 Lee Chuk Munn. the button returns to a black background and red foreground color pair. mouseExited(null).A Button Example 7. you must import java. To capture AWT events.2. Register the listener with the event source which in this case is the RolloverButton. line 6.lang. import java. we are the source as well as the listener. import java.event. The code is as follows: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import java. } public void mouseExited(MouseEvent mEvt) { setBackground(Color. We register with RolloverButton that we are interested in receiving mouse events. setForeground(Color. } public void mouseEntered(MouseEvent mEvt) { setBackground(Color.

setLayout(new FlowLayout()).out. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import java. The others have empty method bodies. one with a rollover face.*. Similarly. when the mouse leaves the button instance. In mouseEntered().addActionListener(new ActionListener() { public void actionPerformed(ActionEvent aEvt) { System. All rights reserved. import java.event. } public static void main(String[] args) { Copyright c July 1999 Lee Chuk Munn. When the mouse enter an instance of RolloverButton.Another Button Example 7. These methods are part of the MouseListener interface and must be implemented by RolloverButton. public class ButtonEventEx extends Frame { public ButtonEventEx() { super("Button Event"). We are only interested in mouseEntered() and mouseExited() method. mouseExited() is invoked. we set the background color to red and the foreground to black.4: A RolloverButton example 7. mouseEntered() will be invoked.lang.7 line 12 to 22.2. 82 .2.println("hello world!"). button. Figure 7. } }). add(button). Note the use of anonymous class to creates a listener in line 9 to 13.*. import java.awt. Figure 7.4 shows 2 instances of RolloverButton.7 Another Button Example The following code prints out “hello world—” whenever the RolloverButton is pressed.*.awt. pack(). RolloverButton button = new RolloverButton("Press Me!").

83 .util. Remember. An example of an event handler method is as below: public void someMethod(XXXEvent xEvt). The steps for creating events is as follows: Define the event object class This is the event object that is passed from the source to the listener. Define the event source This could be any class that is firing the event.setVisible(true). • Call your event class XXXEvent according to the JDK naming conventions.util. Copyright c July 1999 Lee Chuk Munn.3 Creating Customized Events How do we create and fire our own events? Short answer: not very difficult. • Every method in the listener interface denotes a specific event.Creating Customized Events 7.1 are fired by invoking specific methods in the listener objects. These firing method is responsible for instantiating the event object and calling the appropriate event handler method. define an event firing method. Each method should return void and take one parameter. • The event class must be a subclass of EventObject which is found in package java. The EventListener interface is a “marker” interface.1 19 20 21 22 ButtonEventEx ex = new ButtonEventEx(). Define the listener interface This is the interface that all listener must implement. which is the event object. } } 7. • Add event registration and deregistration method.3. • The event interface is call XXXListener according to the JDK naming conventions. These methods has the following forms: public void addXXXListener(XXXListener l) public void removeXXXListener(XXXListener l) • For each event handler method in the listener interface. • Define an interface that extends EventListener interface which is in package java. events in the JDK 1. All rights reserved. ex.

The event object will have a read only property called amount which gives the amount deposited or withdrawn. Getter for the amount properties. public AccountEvent(Object src. public class AccountEvent extends EventObject { private float amount.util. The event will contain the amount deposited or withdrawn. 7.*. line 7.lang. } } The explanation is as follows: line 2. float amt) { super(src).3. The constructor takes 2 parameters.util package because the EventObject class is in it. src is the event source and amt is the amount deposited or withdrawn. This is because event objects are considered immutable so there are no setter methods.3. Remember to import java. 84 . Notice that this is a read only property. All rights reserved. line 10 to 12. 7.3 7.2 The AccountEvent Object Information pertaining to a particular transction in Account is encapsulated in the AccountEvent an event object. The code for AccountEvent is as follows: 1 2 3 4 5 6 7 8 9 10 11 12 13 import java.3 AccountListener Interface The AccountListener interface contains event handling methods that will be called when a specific event occurs.1 Account Class Again We will now add additional features to Account class which will allow any instance of Account to fire an event whenever we deposit or withdraw from it. Java convention dictates that these event handling methods be defined in an interface that is a subclass of Copyright c July 1999 Lee Chuk Munn. amount = amt.AccountListener Interface 7. } public float getAmount() { return (amount).3. line 6. import java.3.*. Calls the superclass’ constructor and sets the event source.

*. So the AccountListener interface looks like this: 1 2 3 4 5 6 7 import java.4 EventListener. listeners = new Vector(). must provide registration and deregistration method. import java. private Vector listeners. } 7.4 Event Listener Registration/Deregistration Inorder for listeners to be notified of potential events. } } public void withdrawal(float amt) { if ((amt <= balance) && (amt >= 0)) { Copyright c July 1999 Lee Chuk Munn. 85 .util.lang.*.*. . the event listeners have to register themseleves the the event source. public void moneyWithdrawn(AccountEvent aEvt). . fireMoneyDeposited(new AccountEvent(this. amt)).*. public interface AccountListener extends EventListener { public void moneyDeposited(AccountEvent aEvt). import java. The event source class. .Event Listener Registration/Deregistration 7. All rights reserved. public abstract class Account { private String name. . A class that wants to handle any of the events defined in the AccountListener interface should implement that interface. public Account(String n. private float balance.3. private Interest interest. The account event registration and deregistration method has the following signature: public void addAccountListener(AccountListener l) public void removeAccountListener(AccountListener l) The required modification to Account class is as follows: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.util. Account in this case.3.lang. int no) { . } public void deposit(float amt) { if (amt >= 0) { balance += amt. .

} public void removeAccountListener(AccountListener l) { listeners. 86 . The Vector class a dynamic array which can be used to store arbitarily objects.addElement(l). } private void fireMoneyDeposited(AccountEvent aEvt) { Vector tmpV. All rights reserved. It is under java. amt)). All listener are kept in the listeners. i < tmpV. 11. As an event source. This is the event registration method. l.removeElement(l). synchronized(listeners) { tmpV = (Vector)listeners.Event Listener Registration/Deregistration 7. 2. . 3. Now lets turn our attention to the code. Account must do the following: 1. Refer to your JDK documentation for details on Vector class.elementAt(i).3. } Before we discuss the lengthy code. } } public void addAccountListener(AccountListener l) { listeners. Notify listeners when an event has occured.size(). Copyright c July 1999 Lee Chuk Munn. Provide event deregistration method.moneyDeposited(aEvt).util package. line 23 to 25. .4 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 balance -= amt. fireMoneyWithdrawn(new AccountEvent(this. When a listener register with us. . we keep a reference of the listener interface. we must remember that Account class is an event source. } } private void fireMoneyWithdrawn(AccountEvent aEvt) { . We will use an instance of Vector called listeners to keep references of listeners who have registered with us to receive event notification. } . } for (int i = 0. i++) { AccountListener l = (AccountListener)tmpV. .clone(). the following lines are noteworthy: line 6. Provide event registration method.

The figure 7. otherwise you will holdup event delivery to other listeners. 87 .4 line 26 to 28. We will look at synchronized in chapter 12. In these 3 lines we go through every listener that have been registered with us and we call the its fireMoneyDeposited() method thus notifying it of the deposit event. Copyright c July 1999 Lee Chuk Munn. control is passed from the event source to the listener. line 31 to 33. This is to prevent new listeners being added while we are notifying the listeners. line 34 to 36.5 illustrates this entire process: A word of caution: event notification is a method invocation. We remove the previously registered listener from listeners.Event Listener Registration/Deregistration 7. The synchronized keyword is to lock listeners while being copied. Before we notify our listeners of an event we first make a copy of the listeners. This is the event deregistration method. It should return the control to the source as soon as possible. After someone has deposited some money. Listeners can choose to stop receiving events by calling this method.3. To do this we call fireMoneyDeposited() method which does the notification. line 16. The event object consist of the source of the event (this) and the amount that is deposited (amt). We also need to pass an event object along with the notification. we need to notify our listeners. The listener should not “hold” the control. All rights reserved.

3. All rights reserved. 88 .4 public void addAccountListener(AccountListener l) Register listener Event Source Fire event listeners AccountEvent Event Listener Reference listeners public class Fred implements AccountListener { public void moneyDeposited(AccountEvent aEvt) { .Event Listener Registration/Deregistration 7.. } } Figure 7.. } public void moneyWithdrawn(AccountEvent aEvt) { ..5: Notifying listeners Copyright c July 1999 Lee Chuk Munn..

1 An Exceptional Example Let’s look at the following code 1 2 3 4 import java. exception travel up the method call stack until it is handled by one of the method.*.1. An exception is an event thrown either by the JVM or by your code to indicate that an error has occured. 8. public class ExceptionEx { public String[] msgs = {"bonjour". 89 . Defensive programming assumes all codes to be erraneous and proceeds to inter spread error checks to normal code. We will then proceed to looking at Java exception mechanism.lang.1 Exceptions Java’s way of defensive programming is via the use of its exceptions mechanism. "chou san". Sometimes you can spend more coding time on checking and handling errors than actually writing your program. Exceptions has the following two benefits: • They allow you to separate error handling code from normal code.Chapter 8 Exceptions Program bugs and program crashes are invevitable unless you plan to continue writing “hello world” for the rest of your life. We will begin our exception discussion by learing how to glean useful information for exception stacks. There is a well defined chain of responsibility. • You can determine exactly who handles an error. 8. Unhandle exception are captured and reported by the JVM. we will end this chapter by creating our very own exceptions.

length) System.1.lang. } public static void main(String[] args) { ExceptionEx ex = new ExceptionEx(). Notice how the exception “travels” from doit() to main() until it reaches the JVM which prints out the exception.Exception Objects 8. Apparently the programer should have written i++ instead of ++i which resulted in the exception.2 5 6 7 8 9 10 11 12 13 14 15 "selamat pagi" }.java file.ArrayIndexOutOfBoundsException: 3 at ExceptionEx. 90 . An example of this output is shown in page 90.println(msgs[++i]).java:13) The stack consists of 2 parts. All rights reserved.2 Exception Objects A exception object is an object that represents the state of the exception. This captured information is the exception object. Copyright c July 1999 Lee Chuk Munn. public void doit() { int i = 0. line 3 indicates the type of exception that has occured and lines 4 and 5 shows the methods on the call stack. } } which will generate the following exception stack example when executed: 1 2 3 4 5 chou san selamat pagi java.main(ExceptionEx. Examining line 9 we find the offending line: System. All exception objects are subclass of Exception1 and has the following methods: public void printStackTrace() Prints out the stack trace at the point of the exception.doit(ExceptionEx. ex. 8.java:9) at ExceptionEx. You can examine the exception object to find out what is wrong and recover from it.out.doit().1. When an exception occurs the JVM captures the environment at that instance. while (i < msgs. 1 Actuall all exceptions are subclass of Throwable. The exception type is ArrayIndexOutOfBoundsException which occurs in doit() method at line 9 in the ExceptionEx.out.println(msgs[++i]).

. Our block of code consist of 1 single line vis. Reseting"). . we will rewrite the example on page 89 to handle the ArrayIndexOutOfBoundsException and recover from it. line 7. The catch defines what exception to catch. This is specified as a formal parameter immediately after catch. if any.1. If such an exception is raised in the exception block. 1 2 3 4 5 6 7 8 9 10 11 12 . } catch (ArrayIndexOutOfBoundsException e) { System. Also. i = 0.println(msgs[++i]).the { } between lines 5 and 7. viz. This is the exception object.3 public String getMessage() Returns the exception’s error message. we get the following output: Copyright c July 1999 Lee Chuk Munn. Notice that the catch block looks a lot like a method declaration. .println("Oops! Busted index.3 try-catch Block A try-catch block establishes a block of code that is to have its exception and abnormal exits handled. . while (i < msgs. note the“e”. When we run the ExceptionEx again. The explanation for the exception code snippet is as follows: line 5 to 7. public void doit() { int i = 0. 8. the block of code that could generate an exception. } } . All rights reserved.out. 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. A catch established what exception that the block should catch and take whatever action necessary to deal with the exceptional condition. 91 . program control is passed to the exception handler.1.out. These lines define the exception block.length) try { System.try-catch Block 8.

92 . Reseting chou san selamat pagi Oops! Busted index... The finally keyword is generally used to clean up after a try or a catch. i = 0. You should always correct a bug rather than using a try-catch to circumvent it. } } . Reseting chou san selamat pagi When i equals to 3.length) try { System. 8. the previous code snippet is modified to catch 2 exceptions as below: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 . 8. .println("Oops! Busted index. Please note that the previous code snippet has a bug in the array access. break.out. When the exception handler completes. the exception object is caught by catch and the exception handler is executed.. it is caught by the first catch block with the appropriate exception object type. This is done by adding multiple catch to the exception block.. You can catch multiple exception within an exception block. line 6 of the code snippet above generated an exception.And finally.4 And finally.1. . All rights reserved.1.out. the program returns to while and the entire process is repeated. } catch (NullPointerException e) { System. It defines a block of code that is always executed regardless of whether an Copyright c July 1999 Lee Chuk Munn. Only one catch block will be executed. } catch (ArrayIndexOutOfBoundsException e) { System. while (i < msgs. . Reseting"). . We see the “Oops!” message printed out and i s reset to 0.4 chou san selamat pagi Oops! Busted index. public void doit() { int i = 0. When an exception is thrown in a multi catch blocks.out.println("Oops! Did not initialize array").println(msgs[++i]).

If we have the following code skeleton try { // Point 1 } catch ( . while ((ch = is. You can also use a finally without a catch clause. Uncaught exception thrown is when an exception is thrown and this exception is not specified in a catch.println(e. .out. } finally { is. int ch.read()) != -1) System. All rights reserved. This category of exception is almost always a RuntimeException. Lets take a look at an example : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 .) { // Point 2 } finally { Copyright c July 1999 Lee Chuk Munn.1. Normal completion is when the code in a try-catch-finally block completes normally. This is also true when you execute a return. continue or break. 8. This is done using a return. The read() method may throw a IOException if it encountered an error during the read. Line 7 reads a character for a FileInputStream. try { fis = new FileInputStream(file).println(ch).getMessage()). continue or break. But regardless of whether an IOExceptiion exception is thrown or not. public void readFile(String file) { FileInputStream fis = null. There are 4 possible scenerios to a try-catch-finally block. . . 93 . } catch (IOException e) { System. .And finally. They are Forced exit is when you forced program control to be passed out of a try block. . } } . We will cover I/O in the next chapter..close(). .4 exception is thrown. Caught exception thrown refers to an exception thrown that is specified in a catch..out. the above code snippet will gurantee to close the file because we have the close() (line 12 ) in a finally block.

close(). Note line 3.println(ch). Point 4 8.Generating Exceptions 8. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 . } finally { is. while ((ch = is. The readFile() method on page 93 is modified so that the caller instead of readFile() is responsible for handling IOException. 8. . .1. Point 3.read()) != -1) System.1.6 Generating Exceptions You can generate your own exception with a throw (note the missing “s”) statement.6 // Point 3 } // Point 4 the execution path of the above mentioned scenerios are as follows: Forced Point 1. Point 3. you use throws to declare that there is an exception to be caught. } } . Point 2. 94 . A throw does 2 things: 1. public void readFile(String file) throws IOException { FileInputStream fis = null. Point 4 Caught Point 1.out. Point 4 Normal Point 1. In this case you must declare the out going exception as part of your method declaration. try { int ch. Creates an exception object. Point 3. All rights reserved. Point 3. .5 Declaring Exceptions Sometimes you may not choose to handle an exception but pass it on the calling method.1. Point 4 Uncaught Point 1. Causes normal program execution to stop. 2. It is the responsibility of the caller to handle it within a try-catch block. This above 2 points is best illustrated with the following example: Copyright c July 1999 Lee Chuk Munn. fis = new FileInputStream(file). .

out. Copyright c July 1999 Lee Chuk Munn. After the throw statement. We will modify OverdrawnException to withdrawal() method.2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 . File fd = new File(file). 95 . try { int ch. . . the program exist the readFile() method. • The date of the transaction. you can also create your own exception objects. while ((ch = is. All rights reserved. We will add exception to Account class. The OverdrawnException will capture all information pertaining to an overdrawn transaction. 8. public void readFile(String file) throws IOException.read()) != -1) System. if it exists we proceed to open and read it. • Overdrawn amount. if (!fd. The explanation for the above code is as follows: we check if the file exists. • Account number.2 Creating Your Own Exception Besides using the JDK supplied exception classes. • Account balance at the time of the withdrawal.println(ch). Notice that you have to instantiate the exception object.close(). . The following code implements OverdrawnException. . we throw a FileNotFoundException (line 7 ). fis = new FileInputStream(file).Creating Your Own Exception 8. But if it does not exists. } } . This requires you to subclass the Exception class.exists()) throw new FileNotFoundException(file). } finally { is. These information includes the following: • Account name. FileNotFoundException { FileInputStream fis = null. The remainding statements in the method is not executed.

private final Date date. } . Since the superclass has a constructor with a String parameter. 96 . name = acct.lang. What we are really saying here is that OverdrawnException object is immtable.util. . To use OverdrawnException. line 11.getName(). private final float withdrawAmount. account number (acctNo) and current balance (balance). balance. The constructor takes an Account object and initializes the account name (name). Note that these members are marked final. } } The explanation for the above code is as follows: line 10. acctNo = acct. public OverdrawnException(Account acct.getAccountNumber(). import java.Creating Your Own Exception 8. line 12 to 16.*. account number. the content of the object cannot be changed. float amt) { super("Overdrawn"). viz. public class OverdrawnException extends Exception { private final String name. we modify withdrawal() of Account class as follows: 1 2 public class Account { . public float getWithdrawAmount() { return (withdrawAmount). You can get this message using the getMessage() method. . private final int acctNo. Copyright c July 1999 Lee Chuk Munn. amount attempted to withdraw and the transcation date.*. balance = acct. The amt holds the amount the the user is attempting to withdraw.2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import java. . are read only properties to name. date = new Date(). . } public String getName() { return (name). once create. All rights reserved. This means that the value of these members cannot be changed. withdrawnAmount = amt. private final float balance.getBalance().

97 . If the amount to be withdrawn is greater than what is in the account. line 7. Declares OverdrawnException and ErroneousAmountException will be thrown from withdrawal(). if ((amt < 0) throw new ErroneousAmountException(this. } catch (OverdrawnException e) { System. line 9. } Copyright c July 1999 Lee Chuk Munn. When we have passed all the necessary checks.println("Overdrawn"). balance -= amt. amt). All rights reserved.out. .println("You have: " + e. . line 6.out.Creating Your Own Exception 8. 1 2 3 4 5 6 7 8 9 . System.getWithdrawAmount()). we do the withdraw. } . amt).2 3 4 5 6 7 8 9 10 11 12 public void withdrawal(float amt) throws OverdrawnException. try { account.withdraw(amt). passing to it all the necessary parameters.getBalance()).println("You attempt to withdraw: " + e. We check if we are withdrawing negative amount. If so we throw a different exception. System. ErroneousAmountException { if (amt > balance) throw new OverdrawnException(this. 8. . . we throw the OverdrawnException.out. The following code snippet show how we use the modified withdrawal(). Assme ErroneousAmountException is defined. } line 4.

out.println(fileName + " is a " + fn. a database. } System. 9. } System. we will look at a code snippet which displays the properties of a given file if it exists.Chapter 9 Streams Most programs use data in one form or another.io package is the File class. . This class provides methods to manipulate the file system which includes deleting files.println(fileName + " is not readable.println(fileName + " is " + fn. .")." :"file. The JDK provides classes for reading and writing streams of data.io package.println(fileName + " does not exists.isDirectory()? "directory. We will also look at the concept of stream chaining. . a socket on the network. These data can be in a local file.exists()) { System. public void fileInformation(String fileName) { File fn = new File(fileName). return.").out. if (!fn.io. listing directories.canRead()) { System.")."). 98 . returning file statistics renaming files and others.length() + " bytes long.*. return.out. The code is shown below: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import java. Recall that in chapter 8 in page 94 we used File to check for file existance. variables or from another program. if (!fn.1 The File Class One of the commonly used classes in java. These classes are part of the java.out.

99 . Do not forget to import the java. line 11. public void delete() Deletes a file. public long length() Returns the size of the file."). The File class has the following methods: public String getName() Returns the file name. . public boolean canWrite() Test if the file is writable.io package. .println(fileName + " is last modified on " + fn. Check if we can read the file. we print out the size and the last modified date. public boolean isDirectory() Test if the file is a directory. line 5. public boolean isFile() Test if the file is a “normal” file.out. Prints out an appropriate message if fileName is a directory.lastModified() + ". public boolean canRead() Test if the file is readable. public boolean exists() Test if the file exists. The explanation for the above code is as follows: line 1. public long lastModified() Returns the last modified date of the file. line 15 to 18.The File Class 9. line 10. } . If the file does not exist we proceed no further. Copyright c July 1999 Lee Chuk Munn. All rights reserved.1 17 18 19 20 System. If we can read the file. public String getParent() Returns the parent part of the file or null if the file name has no parent part.

1 shows all the subclasses of InputStream. public int read() Reads the next byte of data from this input stream. If no byte is available because the end of the stream has been reached. 9.1. Prior to JDK 1. The concept of 16-bit character streams was introduced in JDK 1. the value -1 is returned. this list is not exhaustive.1 public String[] list() Returns a list of files in a directory. the idea of a stream is the same. to read character streams. The InputStream and Reader classes are input streams. Copyright c July 1999 Lee Chuk Munn. Figure 9.io package only supported 8-bit byte streams. 100 . public long skip(long n) Skips over and discards n bytes of data from this input stream.2 Character and Byte Streams Streams are data sources that we read and write to serially. This method blocks until input data is available. InputStream has the following methods.2. The value byte is returned as an int in the range 0 to 255. All rights reserved. Similarly. Both the character and byte stream classes are quite similar in their use so we will just concentrate on the byte stream and leave character stream classes as an exercise for the reader.InputStream 9. Also all the above methods throws IOException. the java. OutputStream and Writer classes are output streams. public int read(byte[] b) Reads up to b. As the name implies. you read from these streams but not write to it. if the current File object is a directory. To read byte streams we use InputStream and OutputStream classes and their subclasses.2. you cannot read from these latter streams. we use Reader and Writer classes and their subclasses.1 InputStream The InputStream class is an abstract and is a superclass of all classes representing input byte streams. public void mkdir() Creates a directory. Whether you are reading a file or a socket connection.1. or an exception is thrown. the end of the stream is detected.length bytes of data from this input stream into an array of bytes. 9.

Recall that InputStream is an abstract class.io and also java. 9. as in PKZIP Copyright c July 1999 Lee Chuk Munn.util. public void write(int b) Writes a byte to the output stream. public void close() Closes this input stream and releases any system resources associated with the stream.2 OutputStream The OutputStream class is an abstract and is a superclass of all classes representing output byte streams. We must use a concrete implementation of it such as a FileInputStream.2. All rights reserved. Figure 9. We cannot use InputStream to do any reading. OutputStream has the following methods.OutputStream 9.2 shows all the subclasses of OutputStream.1 summarize all input stream classes available in java. these methods throw IOException. Table 9. 101 . 1 Yes.zip1.2 InputStream SequencedInputStream PipedInputStream FileInputStream StringBufferInputStream ByteArrayInputStream FilterInputStream DataInputStream BufferedInputStream PushbackInputStream Figure 9.2. ZIP.1: InputStream class hierarchy public int available() Returns the number of bytes that can be read from this input stream without blocking.

public void flush() Flushes this output stream and forces any buffered output bytes to be written out. public void close() Closes the output stream.zip.util. This class is found in java. and then returns bytes from the buffer. Reads bytes sequentially from an array. Reads bytes sequentially from a file. The superclass of all byte input stream. Table 9.2.2 summerizes all the OutputStream classes in java. making small reads more efficient. Adds a fixed-size “pushback buffer” to an input stream. Reads bytes written to the PipedOutputStream to which it is connected.1: Input stream classes public void write(byte[] b) Writes b.io and java. This is the superclass of GZIPInputStream and ZipInputStream.3 Class Name BufferedInputStream ByteArrayInputStream CheckedInputStream DataInputStream FileInputStream FilterInputStream GZIPInputStream InflaterInputStream InputStream ObjectInputStream PipedInputStream PushbackInputStream SequenceInputStream ZipInputStream Description Reads a buffer of bytes from an InputStream. Reads bytes sequentially from two or more input streams. This class uncompresses entries in a ZIP file.util. It is advisable call flush() before closing. so that bytes can be “unread”. Coputes a checksum of the bytes it reads from an InputStream. The superclass of byte input stream filter classes. Reads binary representations of Java objects and primitive values from a byte stream.length bytes from the specified byte array to this output stream.zip. All rights reserved.OutputStream 9.zip. as if they were a single stream.util. This class uncompresses GZIP compressed bytes it reads from an InputStream. Copyright c July 1999 Lee Chuk Munn. 102 . Reads binary representations of Java primitive types from an InputStream. This class is found in java. Table 9.

103 .out.").println("java FileCopy <src> <dst>").io. FileOutputStream dstFile = new FileOutputStream(args[1]). } if ((new File(args[1])).").exit(-1).println(args[1] + " will be overwritten.out. } int c.exists()) { System.*.*. System. import java. public class FileCopy { public static void main(String[] args) throws IOException { if (args. Copyright c July 1999 Lee Chuk Munn.length != 2) { System. } if (!(new File(args[0])).3 OutputStream PipedOutputStream FileOutputStream StringBufferOutputStream ByteArrayOutputStream FilterOutputStream DataOutputStream BufferedOutputStream PushbackOutputStream Figure 9. System.lang.2. All rights reserved.exit(-1). FileInputStream srcFile = new FileInputStream(args[0]). 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.exit(-1). System.exists()) { System.A File Copy Example 9.3 A File Copy Example We will now write a copy program in Java using FileInputStream and FileOutupStream.2: InputStream class hierarchy 9.2.out. The explanation will follow the code.println(args[0] + " does not exists.

read()) != -1) dstFile. Compress and write bytes out using the GZIP algorithm.close(). The superclass of all byte output stream filters. This class is found in java. 104 .util. dstFile.zip. Computes a checksup of the bytes written to an OutputStream.2: Output stream classes 21 22 23 24 25 26 27 28 29 30 try { while ((c = srcFile. } } } line 2. The superclass of all byte output streams. Writes bytes sequentially to an array.zip.A File Copy Example 9.3 Class Name BufferedOutputStream ByteArrayOutputStream CheckedOutputStream DataOutputStream DeflaterOutputStream FileOutputStream FilterOuputStream GZIPOutputStream ObjectOutputStream OutputStream PipedOutputStream ZipOutputStream Description Buffers byte output for efficiency. Writes bytes sequentially to a file. Copyright c July 1999 Lee Chuk Munn.2. line 6 to 9.close(). line 5. This class is found in java. Writes binary representations of Java primitive types to an OutputStream. Writes bytes to the PipedInputStream to which it is connected. dstFile. } finally { srcFile.write(c). Writes binary representation of java objects and primitive values to an OutputStream. The main() thorws IOException. Table 9. Checks if we have enough parameter. We need a source file to copy from and a destination file to copy to. Do not forget to import java.flush(). the superclass of GZIPOutputStream and ZipOutputStream.io package. All rights reserved. write to an OutputStream only when the buffer fills up. Compress and write bytes to a ZIP file.util.

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. The source code for creating the chain shown in figure 9.3 is as below: 2 GZIP is GNU Zip Copyright c July 1999 Lee Chuk Munn. line 24. Stream chaining is a way of connecting several stream classes to work together to provide new functionalities. This is how the chain works. we can chain these classes so that whatever value that we write will be compressed before saving to a file.3 illustrates this chain. we write to dstFile. line 22.3 Stream Chaining The java. when values are written to DataOutputStream. they are converted to a portable binary format before forwarding to GZIPOutputStream.3 line 10 to 13. line 20. Assume we have GZIPOutputStream2 and DataOutputStream class. this is known as stream chaining. Use FileOutputStream to open destination file for writing. the files are first closed before throwing an exception (line 5 ). FileInputStream is a node stream. After reading the byte. Remember we are copying to this file. 105 . Keep reading a byte from srcFile until we hit an end of file which is denoted by a -1. Filter stream These are layered onto of node streams and provide additional functionalities that are not found in node streams. The finally clause here ensures that all opened files will be closed. line 25. 9.io packages distinguishes between 2 type of streams: Node stream This type of streams read or write from a specific place such as a disk or from the network.Stream Chaining 9. line 23. The idea of stacking filter stream classes on node streeam is one of the most powerful feature in the Java I/O package. force any remainding bytes in the output buffer to the disk. mix and match”. All rights reserved. Use FileInputStream to open source file for reading. Figure 9. If we some how encountered an IOException in line 22 or 23. When we have completed copying. line 19. GZIPOutputStream then compresses the data before passing it to FileOutputStream for saving. Its “plug and play.

which is FileOutputStream. public class WriteChain { public static void main(String[] args) throws IOException { FileOutputStream fos = new FileOutputStream("output. Here. The file name that we will be writing our data to is “output.*. the GZIPOutputStream which does all the compression. we instantiate the first of our filter stream.gz"). line 8.3: Stream chaining example 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import java.*. try { dos.close(). Notice that this filter stream is layered on fos.gz”. } } } The explanation for the above code snippet is as follows: line 7.Stream Chaining 9.zip.writeUTF(args[0]).util. We create a FileOutputStream which is our node stream. dos. 106 .*.io. Copyright c July 1999 Lee Chuk Munn. } finally { dos. import java. GZIPOutputStream gzos = new GZIPOutputStream(fos). DataOutputStream dos = new DataOutputStream(gzos).3 Data DataOutputStream Convert to portable binary format GZIPOutputStream Compress data FileOutputStream To disk Figure 9.lang. All rights reserved. import java.flush().

In this case it is dos. 4. 107 . Provide additional read and/or write methods if necessary. Lets look at AccountOutputStream first. The advantages of the decorator design is as follows: • Add function to objects dynamically and transparently with out affecting other objects. All rights reserved. • Functions can also be revoked dynamically and transparently.2 line 9. we use gzos. 2. When closing a chained stream. line 12. Copyright c July 1999 Lee Chuk Munn.3. The decorator keeps our object simple. 9. The steps for creating a filter stream is a filter streams is as follows: 1. Do not forget to force the data to the hard disk. simple and focused objects that can be combined with other objects to provide new functionalities.Performing I/O with Account 9.2 Performing I/O with Account The best way to understand how a filter stream works is to actually write one. Extend the FilterInputStream or FilterOutputStream. We now add another filter stream on to the chain. We will first detail the steps involved followed by an implementation of the above mentioned 2 classes. line 11. Instead you write small. The filter stream has the following new methods: public void writeAccount(Account acct) Writes acct to a stream. Write a constructor that accepts an InputStream or an OutputStream respectively. We now can write a String to our chain. Override read() or write() if necessary. 9. you do not have to write a complex object with all possible features.1 Decorator Design Stream chaining is a well known design in object oriented software. line 14.3. you only need to close the top most stream class because the dos. Notice that when instantiating DataOutputStream. We will write a AccountInputStream and AccountOutputStream that writes and reads Account objects. Its formal name is known as decorator or wrapper. 3.close() method call will automatically trigger other close() through all the chained classes.3. You always write to the stream class at the top of the chain.

acct. The END_OF_FIELD constant is a value to separate the Account members when we write the members to a OutputStream.io. balance and overdraft as an Account object to a stream.2 public void writeAccount(String name. float balance.getBytes()). int acctNo . import java.isOverdraft()). write(END_OF_FIELD).*.getName() . line 5.valueOf(overdraft).3.lang. acctNo. Our constructor needs to accept a OutputStream. write(END_OF_FIELD). we know where one member ends and another begins. } } line 4. boolean overdraft) Writes name.getBytes()). This is so that when we read the values back.getAccountNumber() . Copyright c July 1999 Lee Chuk Munn. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import java. write(String. boolean overdraft) throws IOException { write(name. All rights reserved.Performing I/O with Account 9. write(END_OF_FIELD). public class AccountOutputStream extends FilterOutputStream { private static final byte END_OF_FIELD = 0. This is in accordance with the filter stream requirements. line 6. acct. write(String.valueOf(balance). Extends the FilterOutputStream.getBytes()). } public void writeAccount(Account acct) throws IOException { writeAccount(acct. int acctNo.getBytes()). public AccountOutputStream(OutputStream os) { super(os). The following code listing implements AccountOutputStream.valueOf(acctNo). write(END_OF_FIELD). 108 .getBalance() . } public void writeAccount(String name. acct. write(String.*. float balance .

line 16. it then instantiate an Account object and returns it to the caller. the account number is “12345”. public class AccountInputStream extends FilterInputStream { private static final byte END_OF_FIELD = 0. You can see that the account name is “Fred Flintstone”. After writing a member. we write the END_OF_FIELD.3. public AccountInputStream(InputStream is) { super(is). Remember a character is 16-bit in Java. readAccount() reads a “record” which consists of a name. line 19 to 26. private int dataPointer. Calls the other writeAccount() which does the writing. buffer = new byte[256].Performing I/O with Account 9. Copyright c July 1999 Lee Chuk Munn.4.*. import java.4: Contents of an AccountInputStream file The classAccountInputStream reads a file written by AccountOutputStream. The method is the workhorse of the class. Once in String. int acctNo = 0. There is $100 in the account with no overdraft capability. A dump of an AccountOutputStream is shown in figure 9. Data for each member is first converted to String using valueOf(). a balance and an overdraft status. All rights reserved. an account number. This write method takes an Account object.*. s 0 t \0 o f n a e l \0 s Figure 9. 109 . float balance = 0F. private byte[] buffer. 000 020 040 F 1 e r 2 \0 e 3 d 4 5 F \0 l 1 i 0 n 0 t . The code that implements AccountInputStream is shown below: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import java. The “\0” is the END_OF_FIELD. The first of our writeAccount() methods.io. the String is written as bytes. line 11 to 14. } public Account readAccount() throws IOException { String name = null.2 line 9.lang.

The readField() method is responsible for reading a field. The size of the buffer is set to 256 bytes. line 32. Remember that a field is denoted by a END_OF_FIELD byte.booleanValue(). All data are stored to an OutputStream as a String. } catch (NumberFormatException e) { throw new IOException("Data file is corrupted. line 12. 110 . return (acct).setOverdraft(overdraft).3. return (new String(buffer. } private String readField() throws IOException { dataPointer = 0.2 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 boolean overdraft = false. try { name = readField(). } Account acct = new Account(name."). line 36. acctNo). We use parseInt(). one byte at a time until we hit a END_OF_FIELD byte.parseInt(readField()). So when we read back the data with the exception of name. acctNo = Integer. overdraft = Boolean. 0.withdrawal(100F). balance = Float. --dataPointer)).Performing I/O with Account 9. acct.deposit(balance). 10. When it has a field. buffer is an internal buffer which we use to hold temporary data. The read byte is stored in buffer. acct. while ((buffer[dataPointer++] = (byte)read()) != END_OF_FIELD).valueOf(readField()).floatValue().valueOf(readField()). acct. line 35. The readAccount() method returns as Account object that is constructed from the information in a InputStream. } } line 6. floatValue() and booleanValue() to do this for us. We read the InputStream. All rights reserved. we need to convert all other fields back to their value. line 19 to 22. These method will throw a Copyright c July 1999 Lee Chuk Munn. readField() converts the field to a String and returns it to the caller. The field held in buffer is converted to a String and returned to the caller.

All rights reserved. we instantiate an Account object. AccountOutputStream aos = new AccountOutputStream(gzos). GZIPOutputStream gzos = new GZIPOutputStream(fos). line 26. Reading the save Account object back is just as simple: 1 2 3 4 FileInputStream fis = new FileInputStream("account.Performing I/O with Account 9. The AccountInputStream and AccountOutputStream classes shows just how simple it is to build on what is provided in java. .gz"). line 28. so we must remove it first before depositing the actual amount.3. Copyright c July 1999 Lee Chuk Munn.gz"). It allows us to build new functionality into our streams modularly.readAccount(). . The code snippet is shown below: 1 2 3 4 5 6 Account acct. In this case we rethrow the exception as IOException.2 NumberFormatException if we fail. lets see how we write a compress Account object to a file. 111 . GZIPInputStream gzis = new GZIPInputStream(fis).io package. Now that we have looked at the implementation. aos. Account acct = ais. FileOutputStream fos = new FileOutputStream("account. . Once we have all the necessary information. AccountInputStream ais = new AccountInputStream(gzis). Stream chaining is a very simple but powerful concept. reporting that we have encountered corrupted data. A new Account always has $100 in it (see page 27) .writeAccount(acct).

Consider the following class and you will begin to appreciate the immensity of problem. You have to save ComplexObjects’s super class SuperComplexObject. For “simple” objects. // methods and constructors . in fact you will have to save all super classes. This is sometimes also known as persistence. how are you going to save this? line 5. When an object is serialized. writing a filter stream may not be as straight forward. only members of the object is serialized. . If there are no getter methods for index. static and final members. including its super class if any.1 Serialization Serialization is the process of “flattening” an object which can then be saved to some permanent storage or passed to another object via OutputStream. public SomeObject someObject. 1 2 3 4 5 6 7 8 public class ComplexObject extends SuperComplexObject { public String name. stream I/O may well be adequate but for “complex” objects. private int index. line 4. methods and constructors are not serialized. 112 . You will also have to save someObject. } Consider the following points from ComplexObject class above: line 2. 10. .Chapter 10 Object Serialization Streams I/O has traditionally been used to save and retrieve “record” type data.

2 ObjectInputStream and ObjectOutputStream The ObjectInputStream and ObjectOutputStream are used to serialize and deserialize objects respectively. If we have a 3 class hierarchy. Serialization of an object begins with the highest serializable class in the object’s class hierarchy. . For Account class to be serializable. The Serializable interface has no methods and only serve as a marker to indicate that it can be serialize.ser file a SavingAccount object. the serialization process also stores the objects’ graph and version. use readObject() and writeObject() from ObjectInputStream and ObjectOutputStream respectively. The following code snippet creates and writes to account. 1 2 .io package. You do not have to implement Serializable on every class. To serialize and deserialize and write objects.1. private float balance.1. All its subclasses will be serializable as well. private int acctNo. we only have to implement the serializable interface as below. Since Account is the base class for all other account classes (eg. 113 . All rights reserved. The process then walks down the hierarchy to serialize data from each subclass in turn.1. just once along the class hierarchy. the class must have the following: • Implement the Serializable interface which is in java. with ClassA at the top. SavingAccount and FixedDepositAccount). its superclass. all of its subclass are serializable. The graph is the objects ancestory viz.2 Besides saving the objects members. if ClassA implements Serializable.4 10. . We will look at versioning in section 10. 10. SavingAccount account = new SavingAccount( Copyright c July 1999 Lee Chuk Munn. . private Interest interest. private boolean overdraft. preferabally in the super class.1 The Serializable Interface To allow an object to be serializable. these subclass will be serializable as well. • Provide a default constructor or a constructor with no parameters. . followed by ClassB and ClassC at the bottom.ObjectInputStream and ObjectOutputStream 10. The Account definition is taken from page 46 1 2 3 4 5 6 7 8 9 public abstract class Account implements Serializable { private String name. public Account() { } .

10. all non primary type member must be serializable if its containing class is to be serialized. In other words.2. To deserialize account. It is much better to re set interest rate calculation after we have deserialized an Account object. we add the transient keyword like so: Copyright c July 1999 Lee Chuk Munn. oos. . . Account account = (Account)ois.2 10. .ser"). balance. we need to serialize that as well. All rights reserved. So that class must implement Serializable as well.flush(). Sometimes we may not want certain members to be serialized. One member that is not a good candidate for serialization is interest for the following reason: • It is transitory in that we can change interest rate calculation.1 3 4 5 6 7 8 9 "Fred". When you deserialize an object. . ObjectInputStream ois = new ObjectInputStream(fis).ser see the following code snippet: 1 2 3 4 5 . acctNo. 12345). name.writeObject(account).readObject(). To denote non serializable fields. .ser. you need to cast the object (line 4 ) back to its original class. But since interest references to a class (which implements the Interest interface). Let’s take a at Account again. Otherwise you will get a NotSerializableException. . overdraft and interest is written to account. oos. FileOutputStream fos = new FileOutputStream( "account. FileInputStream fis = new FileInputStream("account. ObjectOutputStream oos = new ObjectOutputStream(fileOut). we mark these members with the transient keyword. 114 . transitory data or data that is not intended to be serialized.Specifying What Gets Serialized 10.1 Customizing the Serialization Process Specifying What Gets Serialized The default behaviour of writeObjec() is to write all the object’s members to an output stream. members that hold sensitive information.2. When account is serialized. . . To mark interest non serializable.ser"). • We cannot be sure that the class that implemented Interest interface also implemented Serialization. Notice that like filter streams. ObjectOutputStream is layered onto a node stream.

Similarly defaultReadObject() reads the non static and non transient members of the current object from an InputStream.2 1 2 3 4 5 6 7 8 9 public abstract class Account implements Serializable { private String name. private transient Interest interest.readObject and writeObject Method 10. private boolean overdraft. . . The idea is that you want to use the default serialization mechanism to serialize all “standard” members before you save any additional data. ClassNotFoundException.2. private int acctNo. private boolean overdraft. A serializable class can implement the following two methods to take over the entire serialization and deserialization process. 115 . private void writeObject(ObjectOutputStream out) throws IOException private void readObject(ObjectInputStream in) throws IOException. private float balance. The writeObject() method is responsible for writing the members of the object to the stream and readObject() is responsible for restoring it. defaultWriteObject() method writes non static and non transient members of the current object to an OutputStream which is exactly the behaviour of serialization. All rights reserved. private float balance.2 readObject and writeObject Method Serialization offers you more control over the read and writing process than mere transient. Our Account will do the following: any attempt to deserialize an Account object that is 60 days old will result in an exception. public Account() { } . private transient Interest interest.2. private int acctNo. The easiest way to write writeObject() and readObject() is to begin each method with calling defaultWriteObject() and defaultReadObject() respectively. The code to perform expiration checks on serialized Account object is as follows: 1 2 3 4 5 6 7 8 public abstract class Account implements Serializable { private String name. 10. public Account() { } Copyright c July 1999 Lee Chuk Munn.

long current = ((((new Date()). All rights reserved.writeLong(((((new Date()). It is up to writeObject() to determine what to persist. ObjectInputValidation has only one method with the following signature: Copyright c July 1999 Lee Chuk Munn.readLong()) is more than 60 days old. } private void readObject(ObjectInputStream in) throws IOException. 10.3 Validating a Deserialized Object In the previous section. During serialization.getTime()/1000)/60)/60)/24.readLong()) > 60) throw new IOException("Object expired!"). When a class implements the ObjectInputValidation interface. . This is additional information not part of Account. line 13. private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject().Validating a Deserialized Object 10. As it turns out. JVM will call validateObject() (from ObjectInputValidation) after the entire object graph have been installed.defaultReadObject(). line 18. defaultReadObject() populates the object with data from the InputStream. . we informally did our validation in the readObject() method. 116 . If the timestime from the stream (in. Use defaultWriteObject() to write the usual members into the stream. line 17. . we throw an IOException. ClassNotFoundException { in. JDK provides a more formal method of performing validation. 20. if ((current .3 9 10 11 12 13 14 15 16 17 18 19 20 21 22 . } . line 12. control is passed to writeObject(). The explanation is as follows: line 10. line 15.in. out. . line 19.getTime()/1000)/60)/60)/24). readObject() is called when an Account object is deserialized. We now write the time (in days since January 1 1970) on the stream as well. We now get the current time (again expressed in days since January 1 1970).

See line 18.writeLong(((((new Date()). Copyright c July 1999 Lee Chuk Munn. To use ObjectInputValidation you must perform the following steps: 1. . 0). Register your validation interface in readObject() method using registerValidation(). . } public void validateObject() throws InvalidObjectException { long current = ((((new Date()). ClassNotFoundException { in. private transient long serTime. public Account() { } . Implement ObjectInputValidation in you class. . Here’s how the new code looks like: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public abstract class Account implements Serializable. write your validation code in validateObject(). line 7.registerValidation(this. ObjectInputValidation { private String name. The explanation for the above code is as follows: line 2.defaultReadObject(). . in. private void writeObject(ObjectOutputStream out) throws IOException { out. serTime is a temporary variable for holding the serialized time. out. Lets rewrite the Account validation using this framework.Validating a Deserialized Object 10. } . . serTime = in.serTime) > 60) throw new InvalidObjectException("Object expired!").defaultWriteObject().getTime()/1000)/60)/60)/24. You have to implement the ObjectInputValidation interface. .readLong(). private transient Interest interest. 117 .3 public voiid validateObject() throws InvalidObjectException. if ((current . . All rights reserved.getTime()/1000)/60)/60)/24). private boolean overdraft. 2. } private void readObject(ObjectInputStream in) throws IOException.

Read in the time stamp and store it in serTime. its version number is matched against that of its class.4 Versioning Versioning allows a serialized object to identify its class during the deserialization process. All rights reserved. line 24. This is our validation method. The version number for a class can be provided with one of the following 2 ways: 1. line 21. line 17.1. If the object has been serialized for more than 60 day. We do the check again. the version is written to an OutputStream along with the object’s state and the object graph during persistance. you cannot deserialize it back to ClassA because this class is no longer the original class. before a class is deserialized. you add a static member call serialVersionUID in you class like so: 1 2 3 4 5 6 public abstract class Account implements Serializable { public static final long serialVersionUID = 1234567890L. You subsequently modified ClassA to include additional members. private String name. so you have to register your validation routine in readObject(). This will be called after the entire object graph has been restored. Let the JVM assign one for you randomly. . As mention previously. To provide a version number for a particular class. Register our validateObject() for registration. line 18. line 19. 2. Copyright c July 1999 Lee Chuk Munn. otherwise you will get an InvalidClassException. Consider the following scenerio: you have an object of ClassA which you have serialized.Versioning 10. read in all the standard members that we have serialized. In JDK 1. So now when you deserialize the old ClassA object. Define one yourself. As usual.4 line 16. private int acctNo. as in the previous incarnation of this code. If they match then the JVM will proceed with the serialization. You can only validate objects as they are deserialized. we throw a InvalidObjectException. 10. 118 . . line 25. .

All rights reserved.Versioning 10. You can examine a class’s serialVersionUID with serialver in the bin directory of the JDK.1. This will not happen if you explicitly provide a serialVersionUID.1: Graphical interface of serialver 1 The algorithm used is the NIST’s Secure Hash Algorithm (SHA-1) Copyright c July 1999 Lee Chuk Munn. 119 . run the following command serialver -show and type the class’ name in the “Full Class Name:” window. The danger here is that the serialVersionUID will change whenever you modify the class.4 If you did not provide a serialVersionUID. JDK will compute1 a version number using the signature of a stream of bytes that reflect the class definition. To view a class’ version number. Figure 10. An example is shown in figure 10.

120 . • Extend URL’s protocol and content. We will nonetheless provide a quick review of of IP address and port numbers. • Multicast programs. This is a 32 bit unique number.1 Addresses and Ports Every server or host that participate in a TCP/IP network requires an IP address. An IP address comprises of 2 parts: Network number The network number (netid) defines a network. • Access URLs as stream so that you can access a web page as if it was a file local to your system. An example of an address is 192.c.d.1. They are shown in Figure 11. In this chapter. All servers with the same netid belongs to the same network.net package. we will examine a client-server program that uses the TCP protocol. The “network” classes in the said package allows a programmer to write the following: • TCP and UDP oriented programs. There are 4 classes of IP address. 11. These classes can be found in java.10.b. IP address are written in dotted form as a.Chapter 11 Networking The Java API includes a set of classes that facilitates writing TCP/IP based network programs. We will assume that the reader is familar with TCP/IP concepts. Host number Servers in the same network must have unique host number (hostid). each digit is an 8 bit value.1.1.

255 Figure 11. 0 . Data for a particular process in the host must be able to identify the intended process uniquely.2 Client-Server Model TCP/IP applications typically consists of 2 parts: a server which provides some service like file. the server will listen on the bound port for incoming client connection. a port number and an IP address uniquely identifies a process in a host. This server process is know as binding and the server is said to be bound to the port number.Client-Server Model 11. If the bind is successful.255 Class C 1 1 0 net id host id 192 . 0 .233 . 0 .1: IP address format Class A networks are for networks with lots of host while class C networks cater for smaller networks. 0 .255 . A host or server connected to a TCP/IP network can be more than one active process at any given time. Copyright c July 1999 Lee Chuk Munn. To create a server side end point. Port numbers are bound to one and only one process at any one time and can be reused if the process has terminated.191 .255 . 0 . This port number.2 Class A 0 net id host id 1 .127 Class B 1 0 net id host id 128 . Communication between end points can occur over either TCP or UDP.255 Class D 1 1 1 multicast address 224 . 121 . In summary. TCP and UDP uses 16 bit integer values known as port numbers. In this phase. the server will enter its second phase. IP address pair is know as an end point. 0 .255 . the server must specify the protocol it wishes to use and a port number. This is known as listening.239 . All rights reserved. To distinguish process in a host. 11. print or authentication and a client which use this service.

A host name or an IP address of the host in dotted notation. Socket toServer = new Server("batcave".2 A client opens a connection to a server by specifying the IP address of the host in which the server resides and the port number which the server is bound to.2. With this 2 pieces of information.Client-Server Model 11. Copyright c July 1999 Lee Chuk Munn. the client can instatiate a Socket object which will connect to the given IP address or host name on the given port. It then listens for client connection. All rights reserved. This entire process is illustrated in figure 11. We use the ServerSocket class to write a server. 2. The client must also specify the same network protocol that the server uses1 . How does the client initiates a connection to a server? The client requires 2 pieces of information: 1. This Socket is the server’s connection with the client. accept() will return a Socket object. Once the connection is established. The client-server program consists of the following 3 classes: 1 All this sounds rather complicated but it is very easy to do with Java. When a client initiates a connection. The ServerSocket has an accept() method which is used to listen for incoming client connection. both client and server calls getInputStream() and getOutputStream. A ServerSocket is instantiated by providing a port number in its constructor like so: ServerSocket server = new ServerSocket(12345). We will now look an an overview of creating a client and server with the JDK. 122 . The server binds itself to a port. The client and server can now communicate once the connection has established. 2. We are now ready to write an account client-server program which serves Account objects to its client. These above steps can be summarized as follows: 1. 3. These streams on the server and client are “crossed” in that data written on the client’s OutputStream will appear on the server’s InputStream and vice versa. 12345). The port number which the server is listening on. The below example connects to a server listening on port 12345 on host batcave. These methods returns an input and output stream. The client establishes a connection to the server residing on host (IP address) listening on port (port number).

Any client that wishes to communicate with AccountServer will use this class.2. The protocol in question here is not the network protocol but application protocol viz. All rights reserved. 123 . OKAY An acknowledgement that the last operation was successful.2.12345) getOutputStream() getInputStream() Figure 11. AccountProtocol contains the following method: Copyright c July 1999 Lee Chuk Munn. The following commands are defined for the protocol: GET Retrives an Account object from the server. the protocol used between the AccountServer and AccountClient application. 11. AccountServerAPI This is a set of API that accesses the AccountServer.2: Interaction between ServerSocket and Socket AccountServer The server program that servers Account objects.1 Server new ServerSocket(12345) accept() Socket() getInputStream() getOutputStream() Client new Socket(“batcave”. PUT Request the server to save a particular Account. AccountProtocol A class that defines the protocol between the server and a client. ERROR Denotes an error has occured.Defining the Protocol 11.1 Defining the Protocol The AccountProtocol is a holder class that contains information passed between server and a client.

getAccountNumber(). public static final int PUT = 1. private final int accountId. accountId = id. } } Lets examine the code: line 2. private final Account account. 124 . The listing for AccountProtocol is as below: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class AccountProtocol implements Serializable { public static final int ERROR = -1. } public int getCommand() { return (cmd). public static final int OKAY = 2. accountId = acct. } public int getAccountNumber() { return (accountId). public int getAccountNumber() Returns the contained account number. account = acct. account = null. All rights reserved. int id) { cmd = c.Defining the Protocol 11. Account acct) { cmd = c. Remember.1 public int getCommand() Returns the command of the protocol. private final int cmd. Copyright c July 1999 Lee Chuk Munn. public AccountProtocol(int c. } public Account getAccount() { return (account). } public AccountProtocol(int c. The Serializable interface ensure that AccountProtocol is writable across the network. public Account getAccount() Returns the Account object contained within the AccountProtocol. public static final int GET = 0. we have to pass one of these objects from the client to server and vice versa.2.

We have seen this in chapter 8. 125 . This is mainly used for creating a protocol that requests an Account object. account and accountId to ensure that once assigned. The file name is the account number with a “. Copyright c July 1999 Lee Chuk Munn. the server will create a new AccountProtocol object with OKAY command and the Account object and returns it to the client. all members are readonly. the Account that we have set also gets serialized as well. viz. line 15 to 19. This is so that what the client knows that it has received the same object that was created at the server and vice versa. The 2 defined protocols. these variable can never be changed.Writing a Server 11.ser” extension. The AccountProtocol object is immutable. an ERROR is returned. line 26 to 28. Remember the validation protocol that we implemented to Account in page 116? All that continues to work here! When a AccountProtocol object gets serialized. If the Account is not found. it does the following: GET Deserialized an Account object using the provided account number and returns the object to the client. line 10 to 14.2 Writing a Server The AccountServer serves Account objects to clients. We do not want the account contained in a AccountProtocol object to change on its way from the server to the client. nothing in it should change. line 7 to 9. Returns the account number of the Account object contain within. • Adding a final modifier to cmd. If the server is able deserialize the Account. Returns the Account object.2. The first constructor accepts a command and an account number. viz. This design decision is reflected in the class in the following manner: • Getter methods only to the properties. 11. The second constructor creates a AccountProtocol using a command and an Account object. When the server receives a command.2 line 3 to 6. All rights reserved.2. line 20 to 22. Returns the type of command represented by a protocol object. line 23 to 25. Accounts objects are stored as serialized disk files. once created.

The flow of the above mentioned protocol is shown in figure 11. Listen on the port by calling accept(). with will acknowledge with OKAY. accept() will return a Socket instance.3: Flow diagram of AccountServer’s protocol To write a server you have to do the following steps: 1. If the server is successful in serializing the object. This instance is connected with the client.Writing a Server 11.2 PUT Serialized the given Account. Create an instance of ServerSocket giving the required port number in the constructor. The AccountServer listing is as follows : Copyright c July 1999 Lee Chuk Munn. Terminate the connection by calling close() on the Socket. 3. 5. the server calls getInputStream() and getOutputStream() on the Socket instance. An ERROR is returned the AccountServer cannot serializes the object. When a client connects. Receives a GET Gets the account Receives a PUT Saves the account true Successful? false Returns OKAY Returns ERROR Figure 11.3. All rights reserved. 126 . To communicate with the client. The OutputStream is attached to the client’s InputStream and vice versa. 4. This will return an InputStream and an OutputStream respectively. 2.2.

public AccountServer(int port) throws IOException { super(port). All rights reserved. try { switch (acctProto.Writing a Server 11..PUT: handlePut(oos.close(). case AccountProtocol.writeObject(new AccountProtocol( AccountProtocol.ERROR: default: } } catch (Exception e) { oos.2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import java. acctProto). clnt. import java.lang. AccountProtocol acctProto = (AccountProtocol)ois. break.ERROR.2.GET: handleGet(oos. 127 . break.getOutputStream()).net.out.io. acctProto). import java. } } catch (Exception e) { } } } private void handleGet(ObjectOutputStream netOOS Copyright c July 1999 Lee Chuk Munn..*. ObjectOutputStream oos = new ObjectOutputStream( clnt. case AccountProtocol. 0)). public class AccountServer extends ServerSocket { public static final int PORT = 12345.").close(). while (true) { try { Socket clnt = accept(). } public void run() { System. } finally { ois.close().*.readObject().println("AccountServer started.*. ObjectInputStream ois = new ObjectInputStream( clnt.getInputStream()).getCommand()) { case AccountProtocol. oos.

Copyright c July 1999 Lee Chuk Munn. line 5.2. ObjectInputStream ois = new ObjectInputStream(fis).ser"). netOOS.getAccount()). We do not have to create a separate ServerSocket just to accept client connection.getAccountNumber() + ".OKAY.2 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 .writeObject(result).close(). oos. The run() method is our main loop. line 11 to 41. oos. netOOS. Remember to import java. 128 . ObjectOutputStream oos = new ObjectOutputStream(fos).close(). oos. accept() waits for a connection. AccountProtocol result = new AccountProtocol( AccountProtocol.readObject()).ser"). } private void handlePut(ObjectOutputStream netOOS . ois.flush(). netOOS. We manually chain the super class’ constructor because ServerSocket does not have a construct with the default constructor’s signature.flush(). it will return with a Socket instance when a client connects.flush(). All rights reserved. AccountProtocol proto) throws Exception { FileInputStream fis = new FileInputStream( proto.writeObject(new AccountProtocol(AccountProtocol. line 9. line 15. In here. netOOS.net package. server.getAccountNumber() + ". The AccountServer is a subclass of ServerSocket.OKAY . (Account)ois. 0)).writeObject(proto. we wait for client connection and process them.Writing a Server 11. AccountProtocol proto) throws Exception { FileOutputStream fos = new FileOutputStream( proto.run(). } public static void main(String[] args) throws Exception { AccountServer server = new AccountServer(PORT). } } Explanation for the AccountServer code is as follows: line 3.

the accept() will have returned a corresponding Socket on the server side. line 44 to 55. All you have to do now is to get the InputStream and OutputStream. All rights reserved. OutputStream os = clnt. line 62. line 34. we read the AccountProtocol object send by the client. Once caveat about getting the InputStream and OutputStream from the server and client side Socket is that you cannot call get the same stream from both side in the same sequence. 66. If any of the handleXXX() methods throw any exceptions. 21.getOutputStream(). To instantiate a Socket. Opens the serialized object file for reading. Starts the AccountServer on port 12345.2. Creates an ObjectInputStream and an ObjectOutputStream from the Socket. Open a file for serializing the Account. line 20. If you successfully create a Socket instance. Consider the following code snippet from the server side: 1 2 3 Socket clnt = accept(). Returns an OKAY status to the client. Creates a AccountProtocol object that contains the requested object.2. handleGet() desrializes the requested account for the hard disk and returns it in a AccountProtocol to the client. you will need the IP address of the host and the port number.Writing the Server API 11. Once we have gotten the input and output stream. We now use a switch statment to distinguish the command that we have received from the client. InputStream is = clnt. line 59 to 60. line 65. Extract the Account and serializes it.getInputStream(). This will cause your program to hang. line 23 to 32. line 47 to 49. line 55 to 68. line 71. line 52. 11. line 50. Sends the AccountProtocol to the client. 51.3 Writing the Server API A client uses the Socket class to initiate a connection to a server. 35. 129 Copyright c July 1999 Lee Chuk Munn. we will send an ERROR back to the client.3 line 16 to 19. handlePut() gets the Account object for AccountProtocol and serializes it to the hard disk. .

If the accountNumber does not exist. Why do we need a AccountServerAPI? Remember abstraction and encapsulation? We want to hide the implementation details for the users.getOutputStream().*. Copyright c July 1999 Lee Chuk Munn.*. InputStream is = toServer.getOutputStream(). public AccountServerAPI(String hn) { 2 APIException listing is not shown.3 Note the call sequence: InputStream frist.*.Writing the Server API 11. If we were to write the following on the client side. InputStream is = toServer. and localize our protocol behaviour to 2 classes: AccountServerAPI and AccountServer.getInputStream(). Okay. The listing for AccountServerAPI is as follows: 1 2 3 4 5 6 7 8 9 import java. import java.net. public Account putAccount(Account acct) Saves acct back to the server. 130 .lang. a null will be returned. private ObjectInputStream ois. OutputStream os = toServer. If the save is successful. 12345). putAccount() will return the Account object that is saved. programmers who will be using our API to develop applications.2. public class AccountServerAPI { private Socket toServer = null. private ObjectOutputStream oos. All rights reserved. lets look at AccountServerAPI. We should reverse the getXXXStream() call sequence like below: 1 2 3 Socket toServer = new Socket("batcave". OutputStream os = toServer. The signature of the constructor 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. this will be equal to acct. our program will hang: 1 2 3 Socket toServer = new Socket("batcave". import java. Both getAccount() and putAccount() throws APIException2. getAccount() will return null. The class has 1 constructor that takes a host name that the server is running on.io. If the save is not successful. private String hostname. 12345).getInputStream().

flush(). AccountServer. } finally { return (result).PORT). else return (null). Copyright c July 1999 Lee Chuk Munn.getCommand() == AccountProtocol.getMessage()). All rights reserved.writeObject(proto). result = (AccountProtocol)ois. } public AccountProtocol write(AccountProtocol proto) throws APIException { AccountProtocol result = null.GET.3 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 hostname = hn. ois = new ObjectInputStream(toServer. else return (null). } catch (Exception e) { close(). if (result. try { oos. oos = new ObjectOutputStream(toServer. } public Account putAccount(Account acct) throws APIException { AccountProtocol result = write( new AccountProtocol(AccountProtocol.getInputStream()).2. 131 . oos.OKAY) return (result.Writing the Server API 11. } public Account getAccount(int acctId) throws APIException { AccountProtocol result = write( new AccountProtocol(AccountProtocol.getOutputStream()). acctId)). if (result. throw new APIException(e. } } private void connect() throws APIException { try { toServer = new Socket(hostname. connect().OKAY) return (acct).readObject().PUT.getAccount()). acct)).getCommand() == AccountProtocol. } try { close().

we then return the Account object to the caller and exits this method. 24.close(). we then return a null. line 28. If the save is not successful. We check the return result if the command is OKAY. line 21 to 29. If it is we return the saved Account object to the caller signifying that the save is successful. 15.getMessage()).2. The getAccount() method returns the an Account from the server when given a valid account number. very likely an ERROR.Writing the Server API 11. We then use write() to write the protocol to the server. toServer. } } private void close() throws APIException { try { oos. line 16. After we have create the protocol. line 14. } } } line 12 to 20. setting the command to PUT and give an Account object that we wish to save. If the command is not an OKAY. Again. we use write() method (see below). } catch (IOException e) { throw new APIException(e. ois. Copyright c July 1999 Lee Chuk Munn. All rights reserved.3 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 } catch (UnknownHostException e) { throw new APIException(e. line 17. line 19.getMessage()).getMessage()). The putAccount() saves an Account object back to the server. We create a AccountProtocol. We check result again to see if the write is successful.close(). 26. line 23. 132 . The result of the GET is returned as another AccountProtocol object. } catch (IOException e) { throw new APIException(e. If the command is an OKAY. setting the command to GET and give the appropriate account number. we create a AccountProtocol object. line 25. we return a null.close().

line 51. line 52.2. Note that write() is a public method. line 37. we will now see how we can use the AccountServerAPI. Connects to the server first. Writes the AccountProtocol to the server. line 39. we closes the stream and notify the caller by throwing an APIException. Returns result which we got from the server back to the caller. This method connects to an AccountServer. it also sets up the ObjectInputStream and ObjectOutputStream for reading and writing later. We create a connection to a server on host hostname which we set in the constructor listening on port AccountServer. line 60 to 69. Create an ObjectOutputStream using the InputStream from the Socket. 36. 11. All rights reserved. line 35. create an ObjectInputStream. Copyright c July 1999 Lee Chuk Munn. The method then reads the reply from the server and returns this to the caller.4 Using the AccountServerAPI Now that we have hide the complexities of handling the protocol in getAccount() and putAccount().4 line 30 to 47. Similarly. You can actually call write() and send you own commands to the server. We then read the result returned by the server.2. 133 . 40. line 48 to 59. The flush() forces the write on the ObjectOutputStream. We will examine the connect() method shortly. We need to create an instance of AccountServerAPI by providing it with the server’s name as in the following code: AccountServerAPI api = new AccountServerAPI("batcave"). line 53. If the writeObject() and readObject() is successful.PORT (12345). oos is set by connect(). ois is set by connect(). line 45. line 43.Using the AccountServerAPI 11. The write() method takes a AccountProtocol object and sends it to the AccountServer. line 33. The close() method closes the opened object streams as well as the connection to the server. we then close the connection to the server. If the above writeObject() or readObject() has any exceptions.

OKAY) { // Error ! Did not get account return. } .Using the AccountServerAPI 11. Copyright c July 1999 Lee Chuk Munn.putAccount(acct). } Account acct = result. result = api. . . All rights reserved. .getCommand() != AccountProtocol.getAccount(). 134 . AccountProtocol result = api. . // process acct .getAccount(12345).4 The following code snippet gets an account 12345 from the server. processes it and saves the account back. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 .OKAY) { // Error ! Save was not successful return.getCommand() != AccountProtocol. . if (result. if (result.2. .

public void run() { System. Consider the code snippet below which is part of the AccountServer shown on page 126: 1 2 3 4 5 6 7 8 9 . Here are just some examples that the JVM uses threads to support your program without your knowledge: • In handling event.. Threads are very powerful concepts in computer science. timers and servers. . Some examples tasks that will benefit from being threaded are asynchronous I/O. They allow us to exploit the natural concurrency that occurs in our program. even then your single threaded program lives in the JVM threaded environment. ObjectInputStream ois = new ObjectInputStream( clnt. we make our program more efficient and responsive. • Object references goes out of scope. • When your AWT window requires repaint because of exposure.getInputStream()).println("AccountServer started. by natural concurrency we mean multiple independent task. the JVM dispatches a thread to call your event handler. ObjectOutputStream oos = new ObjectOutputStream( 135 .. like taxes are always present in the JVM. while (true) { try { Socket clnt = accept(). the paint() is called by a thread.out.Chapter 12 Threads and Synchronization Threads. . a thread called the garbage collector is used to free the memory. By creating threads to handle these independent tasks. Threading is such an integral part of the JVM that it is almost impossible to write single threaded program save for hello world.").

At this point. This thread is called the primordial thread. try { switch (acctProto.1 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 clnt. This is one instance where we can use thread to make our program more efficient and responsive by creating a thread to handle the client while the server’s thread returns to wait in accept(). the client is forced to wait until the server returns to accept() to accept the connection. • Statemets from a thread’s starting point are executed according to their sequence. 136 . A Java program will always start executing at main(). A thread can access all local variables and member variables. But since the server is in handleGet(). . .getCommand()) { // Process command } } catch (Exception e) { . This thread will hang in accept() until it receives a connection. . a section of code executed independently of other threads within a single program. . . .getOutputStream()). When the server starts. the JVM creates the first thread to execute the server.What is a Thread? 12. All rights reserved. 12 ) and proceeds to handle the contained command (line 14 to 16 ) by calling the appropriate handleXXX() method. the server returns from accept() and reads in the AccountProtocol object (line 11. Copyright c July 1999 Lee Chuk Munn. } finally { . We will return to this example a little later and mutithread it. AccountProtocol acctProto = (AccountProtocol)ois. } } catch (Exception e) { } } } .readObject(). A thread has the following characteristics: • Threads start their execution at a well know point just as Java programs start their execution at a well known point. another client contacts the server. The server has just received a client connection and is presently in handleGet() method. When a client connection comes in (line 6 ). 12.1 What is a Thread? So what exactly is a thread? A thread is an execution path viz.

Once you have understand this approach.println(msg). We will leave this as an exercise for the reader1 .1 • Threads are independent of each other. public ThreadedMessage(String m) { msg = m. believe that the second method is more flexible because you can always implement more than 1 interface but subclass only on class. Subclassing Thread is in fact a specialization of the first method. the thread is said to have completed and therefore dead. You can either 1.lang. implements the Runnable interface. it will execute the run() method. The interface contains only 1 method and is define as below: public interface Runnable { public void run(). subclass Thread class. So we will look at creating threads from the Runnable interface perspective.out. Consider the below code: 1 2 3 4 5 6 7 8 9 10 11 import java.1.Creating a Thread 12. All rights reserved. their execution order is consider to be non-deterministic viz. To create a thread. or 2.1. you cannot predict the order of execution of the threads. } You class that implements Runnable must implement run().1 Creating a Thread There are 2 ways that you can create a thread with JDK.*. } } 1 Hint: think of subclassing and overriding. public class ThreadedMessage implements Runnable { private String msg. The run() method is very important to a thread because it is the thread’s starting point just as main() is a Java program’s starting point. Copyright c July 1999 Lee Chuk Munn. 12. } public void run() { System. creating threads by subclassing Thread is very easy. When the thread has completed executing run(). When a thread starts. 137 . you must implement the Runnable interface.

ThreadedMessage msg0 = new ThreadedMessage( "Hello threaded world #1"). we are asking thr0 to execute msg0 as a thread. the Thread instance will start running as a bona fide thread. line 2 to 7. The above code deserves a little more explanation. .1 shows the interaction of the threads. When we call start() on the Thread instance. we are merely giving this class the capability to run as a thread. Figure 12. ThreadedMessage msg2 = new ThreadedMessage( "Hello threaded world #3"). When we pass an instance of ThreadedMessage . Write code in run() method.1 line 3. At this point.Creating a Thread 12. these code will be executed by the thread. . Implement the Runnable interface in your class. we will now make it run as one. By implementing the Runnable interface. thr2. line 8 to 10. We implement the Runnable interface if we want this class to run as a thread. . msg0 for example. line 11 to 13. Therefore. line 8 to 10. Thread thr2 = new Thread(msg2). Now that we have a class which is capable of running as a thread. The ThreadedMessage class is not a thread yet. . We create 3 instances of ThreadedMessage. the JVM will start thr0 as a thread. All rights reserved. creating a thread involves the following steps: 1. Thread thr0 = new Thread(msg0). ThreadedMessage msg1 = new ThreadedMessage( "Hello threaded world #2"). thr0 will start executing run(). The run() method which we must implement.1. When we call start(). At this point thr0 is not a thread yet. to an instance of Thread (thr0).start().start(). Now we create 3 instances of Thread. . thr1. Nothing fancy.start(). Copyright c July 1999 Lee Chuk Munn. The thread thr0 is said to complete when it has completed executing run(). These are just your regular instance. Thread thr1 = new Thread(msg1). The Thread class takes a Runnable interface in its constructor. thr0. The following code snippet shows how: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 . 138 .

daemon threads are those threads that provide certain services like clocking and watchdog. these thread are known as user thread. public void start() This method starts a thread.1. giving it the class that implements the Runnable interface in the Thread’s constructor. . public void setDaemon(boolean d) Sets if the thread is a daemon thread viz. All rights reserved. Figure 12.1. 3. Call start() on the Thread object. a worker thread. Note that you cannot restart a thread with this method if a thread is completed. A Java program will not exit if there are user 139 Copyright c July 1999 Lee Chuk Munn. The definition of is alive is the thread has not completed executed the run() method. When you create a thread. By contrast. Instantiate a Thread object.2 Thread msg2 msg1 msg0 primordial 2 4 6 8` 9` 10 11 12 13 Line no. You have to recreate the thread instance.Thread Class 12. lets examine some useful methods in the Thread class.1: Time/thread graph 2.2 Thread Class Now that we know how to create threads. 12. User thread are threads that are performing your code. public boolean isAlive() Checks if a thread is alive. by default.

MAX_PRIORITY • Thread. public void setName(String name) Sets a user friendly name to your thread. We will look at locks in the following section.2 threads which are still alive.3.lang.*.*. class ConnectionHandler 140 Copyright c July 1999 Lee Chuk Munn. accept() will return a Socket instance. . This method can only be called before you call start().*.MIN_PRIORITY • Thread.1. All rights reserved. • This Socket will passed to a thread called ConnectionHandler which is responsible for handling client’s requests. You can set a thread to be daemon by calling this method with true.net. public void yield() Causes the current thread to temporarily stop executing so that other threads can have a chance to execute. A thread can be in one of the following 3 priorities: • Thread. When a thread is a sleep it does not loose ownership of the locks that it is holding. java.io. public void sleep(long time) Causes the thread to cease execution for a period of time (in milliseconds).1. the listing is as below: 1 2 3 4 import import import public java.Thread Class 12.NORM_PRIORITY You can set any priorities between the range of MAX_PRIORITY and MIN_PRIORITY inclusive. We will look at priorities in section 12. • The server thread (primordial thread) will return to accept() to wait for other client connections. public void setPriority(int p) Changes the priority of the thread. public native static Thread currentThread(int p) Returns the thread that is executing the current object. java. Lets look at the ConnectionHandler first. We will now rewrite AccountServer that it allocates a thread for each connection. AccountServer now behaves as follows: • When the server receives a connection.

getMessage()). acctProto).1.Thread Class 12. } Copyright c July 1999 Lee Chuk Munn.getInputStream()). } } private void handleGet(ObjectOutputStream netOOS .out. private Socket clnt. 141 .ERROR.2 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 implements Runnable { private ObjectInputStream ois. try { switch (acctProto. . case AccountProtocol.getCommand()) { case AccountProtocol. All rights reserved. oos. public ConnectionHandler(Socket sock) throws IOException { clnt = sock. break.close(). AccountProtocol acctProto = (AccountProtocol)ois. break. AccountProtocol proto) throws Exception { // as before .PUT: handlePut(oos. oos = new ObjectOutputStream(clnt. clnt. } public void run() { try { ois = new ObjectInputStream(clnt.println(e.ERROR: default: } } catch (Exception e) { oos. acctProto). } } catch (Exception e) { System. oos.close(). } finally { ois.writeObject(new AccountProtocol( AccountProtocol. .close().GET: handleGet(oos.readObject(). case AccountProtocol. 0)). private ObjectOutputStream oos.getOutputStream()).flush().

import java.run().*. } catch (Exception e) { System.net.out. When the server receives a client connection. public class AccountServer extends ServerSocket { public static final int PORT = 12345.. } } } public static void main(String[] args) throws Exception { AccountServer server = new AccountServer(PORT). import java. . Most of the “multi threading” logic is between between lines 15 to 17.. 142 . } public void run() { System.start().io.getMessage()). The following is a multi threaded version of the original AccountServer: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 import java.2 49 50 51 52 53 54 55 private void handlePut(ObjectOutputStream netOOS .1. } } If you examine the ConnectionHandler class you would have notice that all the the code is exactly from AccountServer. AccountProtocol proto) throws Exception { // as before . All rights reserved.*. The bulk of the code which was previously in a while loop is now in a run() method (line 13 to 42 ). . server.Thread Class 12.println(e.*.out.").println("AccountServer started. thread. while (true) { try { Thread thread = new Thread( new ConnectionHandler(accept())). public AccountServer(int port) throws IOException { super(port).lang. it creates a ConnectionHandler to handle the client. Copyright c July 1999 Lee Chuk Munn. } } Notice how simple AccontServer has become.

143 . A runnable thread does not mean that the thread is actually running. This is for the thread scheduler to decide. Blocked A blocked thread is one that cannot run because it is waiting for some resource or some events. All this state says is that the thread is ready to run. After the first Copyright c July 1999 Lee Chuk Munn.1.Enhancing AccountServer 12. At this point the ConnectionHandler thread will handle the client’s requests (in run()) while the server thread returns to wait for other client connection (line 15 ).2 show the life cycle of a thread and its transistion between the various states. 12. Consider the following scenerio: A client connects to the server and request account number 12345. The connection between the client and the server is now severed.3 Priorities You can give priorities to threads. 12. Exiting When a thread has completed its run(). This behaviour is codified in AccountServer and AccountServerAPI in chapter 11. lets return to look at the current state of our AccountServer.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 until start() is called. Runnable A thread is in its runnable state after its start() is called. The server deserializes the account and returns it to the client. sleep() A thread which calls sleep() will temporarily (for the duration of the sleep time) stop executing and give lower priority threads a chance to run. A higher priority thread will preempt a lower priority thread. This is done with the setPriority() method. All rights reserved. The default priority for all threads is Thread. 12. The following methods suspends the execution of the calling thread and gives other threads a chance to execute: yield() When a thread calls yield().2 Enhancing AccountServer Before we proceed further with threads.2 The ConnectionHandler instance is started as a thread.1.NORM_PRIORITY. it stops executing temporarily and give threads of higer or equal priority a chance to execute. Figure 12.

the server must now check if the account is on the checkout list. we just serializes it. it is taken off this list. 3. 2.2: Life cycle of a thread client has request 12345. If the account has not been checked out.2 new Thread() start() yield() or preempted Initial Runnable wait() completes run() notify() Exiting Blocked Figure 12. the ConnectionHandler thread checks the requested account number against a requested list. If the client sends a PUT command. When the checked out account is later save.Enhancing AccountServer 12. the thread will return the requested account with an OKAY status. All rights reserved. The new behaviour for AccountServer is as follows: 1. We could not possibally return the account to another client because this would cause account 12345 to be inconsistent. It spawns a ConnectionHandler thread and passes it the connection. If it is. the server must know what Account objects have been requested. 4. The server needs to keep a checkout list so that any subsequent request for account found on this list will be rejected. If the account is not on the list. a second client connects and request the same account. To solve this problem. 144 . Copyright c July 1999 Lee Chuk Munn. INUSE to the client. But if the account has been checked out. the thread will return a new status. The server receives a client connection. If the command is a GET. the server must remove it from the list after serializing the account.

All rights reserved. hashtable is a structure that allows you to store data by associating the data with a unique key.2 5. Copyright c July 1999 Lee Chuk Munn. public boolean containsKey(Object key) Test if the hashtable contains key. public Object remove(Object key) Deletes the key from the hashtable. Briefly. Receives a GET true Checkout? false Receives a PUT Saves the account Returns ERROR Remove from checkout Returns INUSE Gets the account Add to checkout true Successful? false Returns OKAY Returns ERROR Figure 12. the previous will be returned and the current data data will take its place.Enhancing AccountServer 12. The modified protocol is shown in figure 12. We will use the following 3 methods from Hashtable: public Object put(Object key.3: A modifed flow diagram of AccountServer’s protocol To implement the checkout list. we employ Hashtable class. Will return null if the key is not in the hashtable. We define an additional command called RELEASE which essentially does the same thing as a PUT except that RELEASE only removes an account from the checkout list. 145 . otherwise the corresponding data is returned. This class implements a hashtable. Object data) Associate the key with data. If the key exists in the hashtable.3.

*.io. private Hashtable checkout.*. import java.Enhancing AccountServer 12. . while (true) { try { Thread thread = new Thread( new ConnectionHandler(accept(). public class AccountServer extends ServerSocket { public static final int PORT = 12345..*. public AccountProtocol(int c. . public static final int INUSE = 3. } Copyright c July 1999 Lee Chuk Munn. Modification to AccountProtocol is as follows. private final int accountId. thread. .out. } .lang. public static final int RELEASE = 4. . 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 146 . private final Account account. checkout)).*. public static final int PUT = 1. private final int cmd. we add the INUSE (line 7 ) and RELEASE (line 8 ) to the list of commands.net. ConnectionHandler and AccountProtocol.out. public static final int GET = 0. checkout = new Hashtable().util. import java. } catch (Exception e) { System. import java. All rights reserved. public static final int OKAY = 2. The following is a listing of the modified AccountServer.getMessage()). These classes are AccountServer. int id) { .println(e.println("AccountServer started. 1 2 3 4 5 6 7 8 9 10 11 12 13 public class AccountProtocol implements Serializable { public static final int ERROR = -1. import java. public AccountServer(int port) throws IOException { super(port).2 All 3 classes that implements the server must be modified. } public void run() { System..start().").

Enhancing AccountServer 12. try { switch (acctProto. case AccountProtocol. .lang. line 8. import java. And finally.*.*. . we now need to pass to the thread checkout. private Socket clnt. private ObjectOutputStream oos. . All rights reserved.getCommand()) { . private Hashtable checkout. the listing for ConnectionHandler. We declare checkout as a Hashtable.getOutputStream()). Everything else in AccountServer remains save for those modifications listed above. Hashtable class is in java.*. } } catch (Exception e) { . A instance of Hashtable is shared by all ConnectionHandler threads.util.io.getInputStream()). line 12. import java. .net. line 19. } public void run() { try { ois = new ObjectInputStream(clnt. 147 . oos = new ObjectOutputStream(clnt. When we create a thread. break. . 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 import java.RELEASE: handleRelease(oos. public ConnectionHandler(Socket sock.util package. Instantiate checkout when we create the server. AccountProtocol acctProto = (AccountProtocol)ois. .readObject(). import java.2 line 4. Hashtable table) throws IOException { clnt = sock. .*. acctProto). The thread will check if a given account is in checkout. Copyright c July 1999 Lee Chuk Munn. checkout = table. public class ConnectionHandler implements Runnable { private ObjectInputStream ois.

ObjectInputStream ois = new ObjectInputStream(fis).readObject(). } private void handlePut(ObjectOutputStream netOOS .2 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 } private void handleGet(ObjectOutputStream netOOS .OKAY. . } public static void main(String[] args) { . oos. ObjectOutputStream oos = new ObjectOutputStream(fos).ser"). oos.writeObject(proto. 148 . account). AccountProtocol proto) { Integer key = new Integer(proto.flush(). checkout. proto). if (checkout. result = new AccountProtocol( AccountProtocol.remove(key). ois.INUSE.getAccountNumber() + ".getAccount()).flush().put(key. AccountProtocol proto) throws Exception { FileOutputStream fos = new FileOutputStream( proto.ser"). if (checkout.writeObject(result).close().Enhancing AccountServer 12.containsKey(key)) checkout. netOOS. netOOS. Integer key = new Integer(proto.flush(). Account account = (Account)ois. The explanation for the modified ConnectionHandler is as follows: Copyright c July 1999 Lee Chuk Munn. } private void handleRelease(ObjectOutputStream netOOS . } else { FileInputStream fis = new FileInputStream(key + ".writeObject(new AccountProtocol( AccountProtocol. All rights reserved.getAccountNumber()).containsKey(new Integer(key))) { result = new AccountProtocol(AccountProtocol.OKAY. 0)). oos. AccountProtocol proto) throws Exception { AccountProtocol result.close(). . } netOOS. account).getAccountNumber()). handleRelease(netOOS. 0). netOOS.

we also check if the command is a RELEASE. The following list this new method and modifications to the AccountServerAPI class. line 61. line 46. Otherwise we retrieve the account as before. All rights reserved. a INUSE is returned. private boolean inuse. line 25. line 66. line 63 to 71. we add a new method to AccountServerAPI called isInUse() which indicates if the last operation on an account is has been checkout by another client. If the requested account is in checkout. line 41 to 45. . Create a key using the account number. line 33 to 51. After we have deserialized the account we now need to put this account in checkout. . line 38. 149 .2 line 14. line 65. If it is we call the handleRelease() method. To accomodate the new INUSE command. line 39. Hold a reference to the Hashtable object that is passed. 1 2 3 4 public class AccountServerAPI { . 26. handlePut() method serializes an account as well as removing the account from checkout. line 52 to 62. The key has to be an object because the put() method in Hashtable only accepts Objects (see page 145). The handleRelease() removes an account from the checkout list. We check if the account is on the checkout list. The handleGet() method is now modified so that it will check checkout first before returning the requested account. In addition to GET and PUT (not shown). Again we create a key from the account number. we return a INUSE command back to the client. line 67 to 69. We use handleRelease() method to remove an account from checkout.Enhancing AccountServer 12. We now check if the account has been requested using the key created from the previous line. public AccountServerAPI(String hn) { Copyright c July 1999 Lee Chuk Munn. If it is we remove it from checkout and returns an OKAY to the client. line 37. If the account has been checked out.

we modified our AccountServer and ConnectionHandler class such that a checkout account will be entered into a checkout list. } . line 28 to 30. } line 3. } catch (Exception e) { close(). 12. . A thread is created (thr1) thread which then checks if 12345 is in the checkout list.INUSE == result.flush(). All rights reserved. inuse = AccountProtocol. we set inuse. 12345 is not on the list. } try { close(). throw new APIException(e. a second thread (thr2) is Copyright c July 1999 Lee Chuk Munn. At this point in time. } . oos. 150 . try { oos. public AccountProtocol write(AccountProtocol proto) throws APIException { AccountProtocol result = null. This method of updating is acceptable if our server is single threaded.getCommand().writeObject(proto).Synchrnonization 12. But it is not.readObject(). . thr1 proceeds to access the account from hard disk but gets preempted.3 Synchrnonization In the previous section. } } public boolean isInUse() { return (inuse). line 17. . Consider the following: a client request for account 12345.getMessage()). result = (AccountProtocol)ois. } finally { return (result). Add a new member inuse which keeps track of the INUSE command. After we have read the return result from the server. . inuse = false. connect(). Checks if the last command involved a checkout account.3 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 hostname = hn.

Upon acquiring the lock. The thread scheduler now continues thr1’s execution. An atomic action is an action that cannot be further broken into smaller actions. the best candidate would be checkout in AccountServer.1 synchronized Keyword We will now introduce the synchronized keyword which is used to acquire a lock. This interaction is shown in figure 12. This is because thr1 has not yet update the checkout list. 12. If we are not succesful. The syntax is as follows: synchronized(<object>){ <body> } The <object> is the object whose lock we are trying to acquire. we should choose the object that best fits the purpose. thr1 completes its request: deserializes 12345. 151 . AccountServer passes the same checkout object to all threads that it creates. As it turns out. we will proceed into the <body>. • When 2 threads tires to simultaneously acquire a lock. The reason for choosing checkout is because this object is shared by all ConnectionHandler threads.3. in other words the deserialization and updating the checkout list actions cannot be interrupted. we could theoretically use any object to act as a lock. every Java object has a lock and since our program is abound with objects. • When a ConnectionHandler thread tries to lock checkout and finds that another thread has acquired the lock. we Copyright c July 1999 Lee Chuk Munn.3. If we are successful. the JVM will arbitrarily assign the lock to a thread. updates the checkout list and returns the account back to the client. the thread will deserialize the requested account and updates checkout. In practise. So how are we going to create an atomic action out of the deserialization and updating actions. In our case. What we need is a way of making the deserialize and updating the checkout list atomic. updates the checkout list and returns the Account object back to the client.4.synchronized Keyword 12. After performing the two actions. 12345 is not on the list. the thread releases the lock. thr2 then proceeds to deserialize 12345. All rights reserved. This is performed by the JVM. It checks the checkout list. we perform the following steps: • A ConnectionHandler thread will try to lock checkout object. the thread will not proceed until the lock has been released and it has acquired it.1 created for another client which also happens to reqests 12345. To implement atomicity.

Continues running. . Returns 12345 to client. Completes deserialization. It is not.4: A race condition will “wait” at synchronized until we acquire the lock. When we exit the <body>. it still holds the lock. } else { Copyright c July 1999 Lee Chuk Munn. Deserializes 12345. private void handleGet(ObjectOutputStream netOOS . 0). Therefore. Terminates. Updates checkout list. the curly brackets ({ }) defines the scope of the lock. Deserializing 12345 but gets preempted. The modifications to ConnectionHandler is as follows: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public class ConnectionHandler implements Runnable { . AccountProtocol proto) throws Exception { AccountProtocol result. It is not. So atomicity is guranteed. private Hashtable checkout. we releases the lock.3.synchronized Keyword 12.1 thr1 Thread is created to GET 12345. . Updates checkout list. . Terminates. Returns 12345 to client.getAccountNumber()). Integer key = new Integer(proto.containsKey(key)) { result = new AccountProtocol(AccountProtocol. Checks if 12345 is on the checkout list. Figure 12. . thr2 Thread is created to GET 12345. All rights reserved. synchronized(checkout) { if (checkout. The <body> is also called a critical region because only 1 thread is allowed in at any one time. 152 . Checks if 12345 is no the checkout list. . If a thread which is holding a lock gets preempted.INUSE .

All rights reserved. ObjectOutputStream oos = new ObjectOutputStream(fos). AccountProtocol proto) throws Exception { synchronized(checkout) { FileOutputStream fos = new FileOutputStream( proto. checkout. 0)).OKAY . account). ois.readObject(). } } line 11 to 24.getAccount()).writeObject(new AccountProtocol(AccountProtocol. } netOOS. Copyright c July 1999 Lee Chuk Munn.1 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 FileInputStream fis = new FileInputStream(key + ".close().OKAY . } private void handlePut(ObjectOutputStream netOOS .getAccountNumber() + ". oos.synchronized Keyword 12. Account account = (Account)ois. AccountProtocol proto) throws Exception { Integer key = new Integer(proto.writeObject(result). This synchronized block (critical region) ensures that deserialization and updating of checkout is atomic. synchronized(checkout) { if (checkout.3. netOOS. ObjectInputStream ois = new ObjectInputStream(fis). result = new AccountProtocol(AccountProtocol.close(). handleRelease(netOOS.flush(). } } private void handleRelease(ObjectOutputStream netOOS .getAccountNumber()). 153 . Note that we have changed nothing in the original code save for enclosing it with a synchronized. proto).flush().ser"). netOOS.containsKey(key)) checkout. oos.flush().ser"). } } netOOS. account).remove(key).put(key. oos.writeObject(proto.

. } } This can lead to dead locks. we forget to lock checkout before we use. Again. • Never write nested synchronized blocks as below: synchronized(anObject) { . Instead of requiring others to synchronized() the object before using. synchronized(anotherObject) { . then this method will update checkout without regard to what handleGet() is doing. What if. But we must remember to explicitly lock the object (checkout in the example above).3. All rights reserved. Just as a GET is atomic. otherwise you are delaying the lock. If handlePut() is not synchronized. so a PUT command must be atomic as well since both handleGet() and handlePut() manipulates the same checkout list. line 45 to 48. if you know that your program is going to be used in a multi threaded. This could lead to performance problem if you have lots of threads waiting to enter the critical region. in our haste. or that the person who is writing threaded programs is a novice and have no notion of thread safeness. we can declare a method to be synchronized as in the example below: public synchronized void someMethod() { .2 Thread Safe Objects We have seen that by using synchronized. Similarly. . So. . the reason should be obvious. 12. when we handle a RELEASE command. } Copyright c July 1999 Lee Chuk Munn. • You should always try to release a lock as quick as possible. This can lead to inconsistencies in the checkout list. 154 . .Thread Safe Objects 12. A few pointers to remember when you are using synchronized: • Create the smallest possible block. we create a critical region which maintains atomicity on all the statements contain therein. . we also need to acquire the lock to checkout before modifying checkout. . make your class thread safe.3.2 line 31 to 39.

Notice that this method does not have the synchronized keyword in its method declaration. we must acquire the lock to the object viz. } } With this new found knowledge. the method body of someMethod() is now considered the critical region. We will explain this shortly. All rights reserved. This method is not synchronized as well. 155 . The listing for Counter is as follows: 1 2 3 4 5 6 7 8 9 10 11 public class Counter { private final int maximum. the object which someMethod() is part of. add() will return true then we have not exceeded the limit. The Counter class has 1 constructor which takes an int.2 When we invoke someMethod().Thread Safe Objects 12. we release. We will call this class Counter. current = 0. the int specifies the number of thread that can be active at any given time. Counter class has the following methods: public synchronized boolean add() Increments the count. public synchronized void release() Decrement the count. public void getCount() Returns the maximum count. current++. When we leave the method. } public synchronized boolean add() { if (current == maximum) return (false). public Counter(int max) { maximum = max. . Copyright c July 1999 Lee Chuk Munn. private int current.3. public void getCurrentCount() Returns the number of currently active thread. false otherwise. This is just a variation of the follow: public void someMethod() { synchronized(this) { . As before. lets modify AccountServer such that we can control the maximum number of ConnetionHandler thread the server can create at any one time. .

} public synchronized void release() { current = (--current < 0)? 0: current. the value of current. the value of maximum. 10. We must acquire the lock to the object (this) before we can invoke this method. line 20 to 22. line 11. Modifications to AccountServer and ConnectionThread is only minimal. The behaviour is nondeterministic. viz. if we have then we return false. But since getCount() and getCurrentCount() does not update count we do not need to lock the object. This is the first of the thread safe method. This prevents unnecessary delay. line 9. } public int getCount() { return (maximum). 156 . The release() method decrements the current variable. we require the invoker of the 2 methods to acquire the object lock first before proceeding. current holds the number of thread that is active at any given time line 8 to 13. As we have pointed out earlier. All rights reserved. line 17 to 19. Otherwise we increment current and return true.3.2 12 13 14 15 16 17 18 19 20 21 22 23 return (true). we do not need to lock the object before invoking getCount(). We check if we have reached the limit. This method returns the maximum count. Returns the number of active thread. 12. We set the variable maximun which controls the number of thread that can be active at any given time. to enforce orderly update of current. The changes to these classes are as follows: Copyright c July 1999 Lee Chuk Munn. line 6. } } line 5. } public int getCurrentCount() { return (current). viz. We cannot have 2 thread calling add() and relase() simultaneous.Thread Safe Objects 12. line 14 to 16. Why? The observant reader will have notice that both add() and release() modifies the current variable.

checkout = table.println("AccountServer started. checkout = new Hashtable(). All rights reserved. } catch (Exception e) { System.out. Let’s turn our attention to ConnectionThread and see how it uses Counter class."). public ConnectionHandler(Socket sock. Now whenever we create a thread. .start(). thr. Counter cnt) throws IOException { clnt = sock. public AccountServer(int port) throws IOException { super(port).Thread Safe Objects 12. 157 . Hashtable table .. .3. } } } . } public void run() { System. checkout. . private Counter count.. line 15. We have hard coded the Counter so that it only allows a maximum 5 threads to be active. .println(e. } The following lines are noteworthy: line 9. while (true) { try { Thread thr = new Thread(new ConnectionHandler(accept() . Copyright c July 1999 Lee Chuk Munn.getMessage()). Create an instance of Counter. . private Counter count. count)). 16.2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public class AccountServer extends ServerSocket { . private Hashtable checkout. 1 2 3 4 5 6 7 8 9 10 public class ConnectionHandler implements Runnable { . count = new Counter(5). will pass to it the count object. .out.

out. When one of the currently running thread terminates. } public void run() { if (!count. .release(). .4 Condition Variables If synchronized allows threads to enter and exit critical region in an orderly manner then condition variables allows one thread to notify another when certain condition exists. .Condition Variables 12. Since every object in the JVM inherits directly or indirectly from Object. If we cannot increment count. we then exit from the thread. we continue executing the thread. } line 14. The following explains these 2 methods: public void wait() Waits for a condition to occur. 158 . it notifies the waiting thread that there is now a slot available for it to run. All rights reserved.add()) return.getMessage()). The waiting thread then resumes execution. we can use condition variables on all objects. try { . we must call release() to decrement the count before we exit. 12. } catch (Exception e) { System. Copyright c July 1999 Lee Chuk Munn. We try to increnemnt count.println(e. then put the next thread in a waiting area. } count. . The wait() method causes a thread 2 It will return false and ConnectionHandler will terminate the thread.4 11 12 13 14 15 16 17 18 19 20 21 22 23 24 count = cnt. To implement condition variables. The condition here is that if current have reached maximum we wait for it to drop below maximum. line 15. line 21. If we are successful. These two methods are found in Object class. When we are done with our processing. we use wait() and notify(). } . A better way to handle this situation might be as follows: When we have reached maximum number of active threads. Consider the following: presently Counter will will terminate a thread2 if there are already a maximum number of thread active.

current = 0. } public int getCount() { return (maximum). the thread releases its lock on an object and waits until another thread notifies it to wake up through notify(). If we have already reached maximum. } public synchronized void add() { if (current == maximum) while (true) try { wait(). calling from within a synchronized block. After a thread is awakened. This method can only be called by the current owner of the lock. } } line 13. Below is a reimplementation of Counter that uses condition variables: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class Counter extends Object { private final int maximum. Copyright c July 1999 Lee Chuk Munn. When wait() is called. Both the above method will throw IllegalMonitorStateException if the caller is not the current owner of the lock. public void notify() This method wakes up a thread that has called wait(). private int current. All rights reserved. public Counter(int max) { maximum = max. it must reacquire the lock before it can proceed.Condition Variables 12. } catch (InterruptedException e) { } current++. The caller of this method must first acquire the lock. viz.4 to wait until it is notified by another thread to stop waiting. break. then we wait until we are notified. } public synchronized void release() { current = (--current < 0)? 0: current. notify(). 159 . notify() arbitrarily awakens just 1 thread.

When thr1 completes. What exactly is static? We know that when we instantiate 2 instance of FixedDepositAccount. try { . But add() will not let thr2 proceed because the maximum has been reached. lets call them thr1 and thr2. Now when thr2 invoke add() by first acquiring the Counter’s lock.5 line 14. . .5. 12. line 20. thr2 also gives up the lock that it is holding. wait() throws InterruptedException. we exit the while loop. . So Counter puts thr2 in a waiting area by invoking wait().out. This interaction is shown in figure 12. the members of both instances are separate in the sense that if we were to Copyright c July 1999 Lee Chuk Munn. you have notice that we have at numerous times preceed member or method declarations with static. } catch (Exception e) { System. In this case we ignore this exception. When we return from the empty exception body we return to the wait() method by virtue of the infinate loop.release(). thr2 awakens but it could not continue yet because it has to reacquire the object’s lock. We now need to modify only ConnectionHandler to change the way we invoke add() as below: 1 2 3 4 5 6 7 8 9 10 11 . it releases the lock. .println(e. When we awakened from wait(). 160 . Notice that both wait() and notify() are called from within a synchronized block. This trigger a call to notify(). When we decrement current. public void run() { count. This is what we mean by saying you have to acquire the object’s lock before invoking either of those methods. } count. thr1 is running and has just called add() so that current is now equals to maximum.getMessage()). it calls release() before it exits. } .Implication of static on Threads 12. .5 Implication of static on Threads During the course of this book. When thr1 exits release(). thr2 then acquires the lock and continues with its execution. .add(). So how does this new scheme works? We have 2 ConnectionHandler threads. we call notify() to wakeup any waiting threads. line 15. All rights reserved.

Calls wait(). } Now if we were to create 2 instances of Fred and perform the following operations on these instances: 1 2 3 4 5 6 Fred flintstone = new Fred(). we might want all instances to share a single member viz.5: wait() and notify() interaction change the name member of one instance via setName(). Calls add(). Sometimes. Consider the following simple declaration: 1 2 3 4 public class Fred { public String name.name = "Mercury". flintstone. Fred mercury = new Fred(). mercury. Acquire Counter’s lock. Got Counter’s lock. Wakes up. 161 . Release lock on exit. By making age Copyright c July 1999 Lee Chuk Munn. release() calls notify(). To achieve this behaviour. thr2 Acquire Counter’s lock. Tries to get Counter’s lock.Implication of static on Threads 12. This is because of the static declaration on age. Cannot proceed. changing a member variable cause all other instances to “see” this change. All rights reserved. public static int age. Continues running. mercury. Calls release(). we preceed a member’s declaration with static.5 thr1 Acquire Counter’s lock. Continues running. Exits release(). Figure 12.age = 45. Release lock and go to sleep. Calls add(). it will not affect the name of another instance. flintstone.age = 40. The result of listing below: flintstone mercury name Flintstone Mercury age 45 45 Notice that both age member are 45 but name remains their respective values.name = "Flintstone". Releases Counter’s lock.

This is because a class method is not associated withy any particular instance. Class methods differ from instance methods in one important way: you cannot use this in a class method’s body. To access a class member. we do the following: Fred. What impact does class methods or members have on thread programming? When a member is declared static. Copyright c July 1999 Lee Chuk Munn. non static members are called instance member since they are local to the instance only. we are declaring that there is only 1 copy of age no matter how many instance of Fred we have instantiated. all other instance sees it.Implication of static on Threads static. Members declared with static are called class members since there is only 1 copy of that member for the entire class. We can access class members without actually instantiating it. When we change a static member. 162 . So if you lock a static member.<class_member> Therefore to access age. we specify the class name followed by the class member.age = 45. All rights reserved. there is only one copy. you are effectively locking out all access to that member. The syntax is as follows: <class_name>. Methods declared with static are called class methods.

1 Core Classes The following listing pertains to the core Account class.*. } } public Account() { } public Account(String n.1F). private boolean overdraft. int no) { name = n. private String name.Appendix A Listing The following is a complete list of all classes pertaining to the Account class that we have used as an example throughout this book. listeners = new Vector(). public abstract class Account implements Serializable { public static final long serialVersionUID = 1234567890L. private Interest interest. balance = 100F. private int acctNo.*. import java.util.*.java import java. private float balance. overdraft = false. import java.1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 Account. public class DefaultRate implements Interest { public float calculate(float amt) { return (balance * 0. A.io. A. acctNo = no.1. 163 . private Vector listeners. The listing is base on ideas that we have developed until chapter 12.lang.

private float rate. amt)). 0. this. } public void withdrawal(float amt) throws OverdrawnException.MONTH)]. amt). 0.1. this. amt).07F.calculate(getBalance())).12F. } public String getName() { return (name). balance -= amt.get(Calendar. if (amt < 0) throw new ErroneousAmountException("withdraw". } public void deposit(float amt) throws ErroneousAmountException { if (amt < 0) throw new ErroneousAmountException("deposit". { rate = monthlyRate[ (Calendar. else return (0F). if (amt >= 0) balance += amt. 0. 0.Account.1F. 0.1F. Copyright c July 1999 Lee Chuk Munn.getInstance()).1 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 interest = new Interest() { private float monthlyRate[] = {0.1F. } public float calculateInterest() { if (interest != null) return (interest. } public float getBalance() { return (balance). } public int getAccountNumber() { return (acctNo). ErroneousAmountException { if (amt > balance) throw new OverdrawnException("withdraw". 0. } public abstract void printAccount().} public float calculate(float amt) { return (balance * rate). } }. All rights reserved. 0. public void setInterestCalculation(Interest i) { interest = i.1F. } public void setOverdraft(boolean b) { overdraft = b. } public void setName(String n) { name = n.0F}. this. 0. amt). 0.1F .1F. 164 .1F.08F. 0.java A. 0.1F. fireMoneyDeposited(new AccountEvent(this. } public boolean isOverdraft() { return (overdraft).

float amt) throws OverdrawnException. } } private void fireMoneyWithdrawn(AccountEvent aEvt) { Vector tmpV. } private void writeObject(ObjectOutputStream out) throws IOException { out. l.in.moneyDeposited(aEvt).defaultWriteObject(). 165 .clone().1.elementAt(i).getTime()/1000)/60)/60)/24.moneyWithdrawn(aEvt).elementAt(i).withdrawal(amt).java A.Account. } } Copyright c July 1999 Lee Chuk Munn. } for (int i = 0.getTime()/1000)/60)/60)/24).size(). l. } private void fireMoneyDeposited(AccountEvent aEvt) { Vector tmpV. out. } for (int i = 0.readLong()) > 60) throw new IOException("Object expired!"). i++) { AccountListener l = (AccountListener)tmpV. ClassNotFoundException { in. i < tmpV. ErroneousAmountException { if (amt < 0) return.writeLong(((((new Date()). i++) { AccountListener l = (AccountListener)tmpV. } } public String toString() { return ("name = " + name + "\n" + "acctNo = " + acctNo + "\n" + "balance = " + balance + "\n" + "overdraft = " + overdraft + "\n"). } private void readObject(ObjectInputStream in) throws IOException. All rights reserved. } public void addAccountListener(AccountListener l) { listeners. if ((current .defaultReadObject(). long current = ((((new Date()). } public void removeAccountListner(AccountListener l) { listeners.size().1 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 fireMoneyWithdrawn(new AccountEvent(this.clone(). deposit(amt). synchronized(listeners) { tmpV = (Vector)listeners. } public void transfer(Account from. i < tmpV. from. synchronized(listeners) { tmpV = (Vector)listeners.addElement(l).removeElement(l). amt)).

*.java import java. amount = amt. balance = acct. public AccountEvent(Object src. } public float getAmount() { return (amount).getAccountNumber(). name = acct. public interface AccountListener extends EventListener { public void moneyDeposited(AccountEvent aEvt). float amt) { super(exName).1.getBalance().java A. } } A. import java.*. date = new Date(). public AccountException(String exName.java import java. } public String getName() { return (name). All rights reserved.util.util.java import java. public void moneyWithdrawn(AccountEvent aEvt).1. } public int getAccountNumber() { return (acctNo).3 1 2 3 4 5 6 7 8 9 10 11 12 13 AccountEvent. public class AccountEvent extends EventObject { private float amount. } A.AccountException. private final Date date. private final float withdrawAmount.2 1 2 3 4 5 6 7 AccountListener.*. private final int acctNo.lang. acctNo = acct. } public float getBalance() { Copyright c July 1999 Lee Chuk Munn.getName().4 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 AccountException. 166 .util.*. import java. withdrawAmount = amt. public class AccountException extends Exception { private final String name.lang.*.4 A. import java.1. Account acct. float amt) { super(src).1.lang.*. private final float balance.

1.abs((new Random()).5 1 2 3 4 Interest.util. } public Date getExceptionDate() { return (date). All rights reserved.java import java. } public float getWithdrawAmount() { return (withdrawAmount).2 Subclass and Implementations The following are classes that either subclass or implemnts one of the previous class or interface. } A. } public void setInterest(float i) { if (interest == -1F) interest = i.java import java.FixedDepositAccount. import java. 167 .2. int acct) { super(n. private float interest.2. } public void setTerm(Date t) { if (term == null) term = t. } public FixedDepositAccount(String n) { this(n. } public float getInterest() { Copyright c July 1999 Lee Chuk Munn. } public Date getTerm() { return (term). Math.*. A.*. public FixedDepositAccount(String n.lang.*. term = null. interest = -1F.nextInt())).lang. public class FixedDepositAccount extends Account { private Date term.1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 FixedDepositAccount. acct).java A. public interface Interest { public float calculate(float amt).1 25 26 27 28 29 30 31 32 33 return (balance). } } A.

2.2.lang. ErroneousAmountException { withdrawal(getBalance()). if (today.withdrawal(amt). System. } public void withdrawal(float amt) throws OverdrawnException.lang.println("Interest rate = " + getInterest() + "%").2 1 2 3 4 5 6 7 8 9 10 11 SavingAccount. public class GenerousRate implements Interest { public float calculate(float amt) { return (amt * 0. 168 . acct).java import java. } } A. } public void withdrawal() throws OverdrawnException. } } A.println("Account name = " + getName()). } public void printAccount() { System. System.java import java.4 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 return(interest).after(term)) super.*.println("Current balance = $" + getBalance()). All rights reserved.out.out.4 1 2 3 4 TightRate. public class TightRate implements Interest { public float calculate(float amt) { Copyright c July 1999 Lee Chuk Munn.out.TightRate.out.2. System.out. System. ErroneousAmountException { Date today = new Date(). public class SavingAccount extends Account { public SavingAccount(String n.*.3 1 2 3 4 5 6 7 GenerousRate.java A. } public void printAccount() { System.println("Account name = " + getName()).lang. int acct) { super(n.5F).2.*.println("Mature on = " + getTerm()).java import java.println("Amount deposited = $" + getBalance()). } } A.out.

AccountServer.java

A.3.1

5 6 7

return (amt * 0.01F); } }

A.2.5
1 2 3 4 5 6 7 8

ErroneousAmountException.java

import java.lang.*; public class ErroneousAmountException extends AccountException { public ErroneousAmountException(String exName, Account acct , float amt) { super(exName, acct, amt); } }

A.2.6
1 2 3 4 5 6 7

OverDrawnException.java

import java.lang.*; public class OverdrawnException extends AccountException { public OverdrawnException(String exName, Account acct, float amt) { super(exName, acct, amt); } }

A.3

Account Server

The following list the account server classes.

A.3.1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17

AccountServer.java

import java.lang.*; import java.io.*; import java.net.*; import java.util.*; public class AccountServer extends ServerSocket { public static final int PORT = 12345; private Hashtable checkout; private Counter count; public AccountServer(int port) throws IOException { super(port); checkout = new Hashtable(); count = new Counter(5); } public void run() { System.out.println("AccountServer started...");

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

169

ConnectionHandler.java

A.3.2

18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33

while (true) { try { Thread thr = new Thread(new ConnectionHandler(accept() , checkout, count)); thr.start(); } catch (Exception e) { System.out.println(e.getMessage()); } } } public static void main(String[] args) throws Exception { AccountServer server = new AccountServer(PORT); server.run(); } }

A.3.2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34

ConnectionHandler.java

import java.lang.*; import java.io.*; import java.net.*; import java.util.*; public class ConnectionHandler implements Runnable { private ObjectInputStream ois; private ObjectOutputStream oos; private Socket clnt; private Hashtable checkout; private Counter count; public ConnectionHandler(Socket sock, Hashtable table, Counter cnt) throws IOException { clnt = sock; checkout = table; count = cnt; } public void run() { count.add(); try { ois = new ObjectInputStream(clnt.getInputStream()); oos = new ObjectOutputStream(clnt.getOutputStream()); AccountProtocol acctProto = (AccountProtocol)ois.readObject(); try { switch (acctProto.getCommand()) { case AccountProtocol.GET: handleGet(oos, acctProto); break; case AccountProtocol.PUT: handlePut(oos, acctProto); break; case AccountProtocol.RELEASE: handleRelease(oos, acctProto); break;
Copyright c July 1999 Lee Chuk Munn. All rights reserved.

170

ConnectionHandler.java

A.3.2

35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88

case AccountProtocol.ERROR: default: } } catch (Exception e) { oos.writeObject(new AccountProtocol(AccountProtocol.ERROR, 0)); oos.flush(); } finally { ois.close(); oos.close(); clnt.close(); } } catch (Exception e) { System.out.println(e.getMessage()); } count.release(); } private void handleGet(ObjectOutputStream netOOS, AccountProtocol proto) throws Exception { AccountProtocol result; Integer key = new Integer(proto.getAccountNumber()); synchronized(checkout) { if (checkout.containsKey(key)) { result = new AccountProtocol(AccountProtocol.INUSE, 0); } else { FileInputStream fis = new FileInputStream(key + ".ser"); ObjectInputStream ois = new ObjectInputStream(fis); Account account = (Account)ois.readObject(); result = new AccountProtocol(AccountProtocol.OKAY, account); ois.close(); checkout.put(key, account); } } netOOS.writeObject(result); netOOS.flush(); } private void handlePut(ObjectOutputStream netOOS, AccountProtocol proto) throws Exception { synchronized(checkout) { FileOutputStream fos = new FileOutputStream(proto.getAccountNumber() + ".ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(proto.getAccount()); oos.flush(); oos.close(); handleRelease(netOOS, proto); } } private void handleRelease(ObjectOutputStream netOOS, AccountProtocol proto) throws Exception { Integer key = new Integer(proto.getAccountNumber()); synchronized(checkout) { if (checkout.containsKey(key)) checkout.remove(key);

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

171

import java.*. } public int getCommand() { return (cmd). public static final int INUSE = 3.*.lang. private final int cmd. public static final int OKAY = 2.*. } public int getAccountNumber() { return (accountId). accountId = a.Counter. public class Counter extends Object { private final int maximum. account = null. } public AccountProtocol(int c.4 89 90 91 92 93 } netOOS.OKAY. public Counter(int max) { maximum = max.java A. 172 .getAccountNumber().4 1 2 3 4 5 6 7 Counter. Account a) { cmd = c. private final Account account. public static final int GET = 0. public static final int PUT = 1. private int current.3.lang.3.flush(). 0)). private final int accountId.io. netOOS.3. public AccountProtocol(int c. int a) { cmd = c.java import java.java import java.writeObject(new AccountProtocol(AccountProtocol. } } A. Copyright c July 1999 Lee Chuk Munn. } public Account getAccount() { return (account). public static final int RELEASE = 4. public class AccountProtocol implements Serializable { public static final int ERROR = -1. accountId = a. All rights reserved. account = a.3 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 AccountProtocol. } } A.

java import java. public AccountServerAPI(String hn) { hostname = hn.java A. inuse = false. import java. } public synchronized void release() { current = (--current < 0)? 0: current. } public APIException(String msg) { super(msg). private ObjectOutputStream oos.6 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 current = 0.*. } } A. 173 . break.net.3. notify().*. } } A.6 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 AccountServerAPI.io.3. private boolean inuse. private ObjectInputStream ois. private String hostname.lang. All rights reserved. public class AccountServerAPI { private Socket toServer = null. public class APIException extends Exception { public APIException() { super(). } catch (InterruptedException e) { } current++.java import java.*.AccountServerAPI. import java.3.5 1 2 3 4 5 6 7 8 9 10 Counter.lang.*. } public Account getAccount(int acctId) throws APIException { AccountProtocol result = write( Copyright c July 1999 Lee Chuk Munn. } public int getCount() { return (maximum). } public synchronized void add() { if (current == maximum) while (true) try { wait().

PUT. 174 . if (result.AccountServerAPI.OKAY) return (result. } catch (Exception e) { close().readObject().getCommand().6 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 new AccountProtocol(AccountProtocol. } public AccountProtocol write(AccountProtocol proto) throws APIException { AccountProtocol result = null. } catch (IOException e) { throw new APIException(e. throw new APIException(e. } public Account putAccount(Account acct) throws APIException { AccountProtocol result = write( new AccountProtocol(AccountProtocol.getOutputStream()).getInputStream()).RELEASE. connect().getMessage()). oos. acctId)). } finally { return (result).GET. } public void releaseAccount(int acctId) throws APIException { write(new AccountProtocol(AccountProtocol. result = (AccountProtocol)ois. if (result. inuse = AccountProtocol.getMessage()).getCommand() == AccountProtocol.3. ois = new ObjectInputStream(toServer.getCommand() == AccountProtocol.getAccount()). } catch (UnknownHostException e) { throw new APIException(e. acctId)).flush(). } private void connect() throws APIException { try { toServer = new Socket(hostname.OKAY) return (acct). try { oos. } try { close(). else return (null). else return (null).java A. } } public boolean isInUse() { return (inuse). } } private void close() Copyright c July 1999 Lee Chuk Munn.writeObject(proto).getMessage()). oos = new ObjectOutputStream(toServer. acct)). AccountServer.PORT). All rights reserved.INUSE == result.

3.close().java A.close().AccountServerAPI. } } } Copyright c July 1999 Lee Chuk Munn. 175 .6 71 72 73 74 75 76 77 78 79 80 throws APIException { try { oos.close(). ois. All rights reserved. } catch (IOException e) { throw new APIException(e.getMessage()). toServer.

Sign up to vote on this title
UsefulNot useful