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

. . . . . . . . . . . .1 FlowLayout . . . . .4. . . . . . . .1 Member Class . 5. .3 Container . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .8.2. . . . . . . 5. . . 5. .6 Graphics . 7. . 5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5. . . . . .4. . . . . . . . . . . . . . . . . . . . . . . . . .6. . . . . . . 5. . . . . . . .1. . . . . . . . . . . . . . .1 paint(Graphics) Method . . . . 5. . . . . . . . . . .1. . . . . . . . . . 5. . . . Copyright c July 1999 Lee Chuk Munn. . . . .1 Button . . . . 5. .1 Referencing Containing Class’ 6.2 GridLayout . . . . .5. . . . . . . . . . . . . . . . . . . . . . .3. . .1 Using Panel in Complex GUIs . . . .3.2 Instantiating Member Classes 6. . . . . . . . . . . . . 5. . . . . . . . . . . . . . . . . . . .4. . . . . . . . . . . . .1 Component and Container . . . . . . . . . . . . .5 List . . . . . . . 5. . . . . . . . .5. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5. . . . . . . .2 Frame . . . . . . . . . . . . . . . . . . . .3 MenuItem and CheckboxMenuItem 5. . . . .3 The Controller . . . . . .4. . . . . . . . 5. . 5. . .2 Checkbox . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4. .1. . . . . . . . . . . . . . . . . . . . . . . .2 The View . . . . . . . . . . .2 repaint() Method . 6 Inner Class 6. . . . . . 5. . . . .4 AWT Components . 5. . . . . . . . . . . . . . . . . . . 5. . . . . . . . . . . . . . . . .5 The AWT Paint Cycle . . . . . . . . .1 Using Font . .7 TextField . . . . .8. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4.7 Customizing Components .2 LayoutManager .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 . . . . . . . . . . .4. . . . . . .4. . .1 The Model .8. . . . . . . . . . . . . . 7 Handling AWT Events 7. . . . . . . . . . . .1 The MVC Architecture 7. . . . . . . . . .2 Menu . . . .4 Choice . . .3 CheckboxGroup . . . . . All rights reserved. . . . . . . 7. . . . 6. . . . . . . 6. . . . . . . . 5. . . . . . . . . . . . . . . .3 update(Graphics) Method . . . . . 5. . . . . . . . . . .3 BorderLayout . . . . .2. . . . . . . . . . . . . . . . . . . . . .6 Label . . . . . .1 Instance Initializers . .CONTENTS 5 Building GUIs with AWT 5. . . . . . . 5. . . 7. . . . . . . . . Members . . . . . . .2 Events . . . . . . . . . . .2. . . . . . . . 5. . . 5. . . . 5.9 AWT Events . . . . . . . . . . 5. .1. . . . . . .2 Anonymous Class . . . . . . . . 5. . . . . . . . . . . . .8 Adding Menus to Frame . . . . . . . . . . 5. . . .2. . . . . . . . . . . . . . 5. . . .1. . .1 MenuBar . . . . .8 TextArea . . . . . . . . . . . . . . . . . . .

2. . . .1 The AWT Event Model . . . . . . . . . . . . . .3. . 9. . . . . . . . . . . . . . . . . . 10 Object Serialization 10. . . . . . . . . . . . . . .. . . . .2 Identifying Source. . . . . . . . . . . . . . . . . . 10. . . . . . . . . . . . . . . . . . .3. . . . . . . . . . . . . . . . . .3 7. . . . . . .3 Event Listener Interface . .5 Event Objects . . . . . . . . .2 Creating Your Own Exception .2 OutputStream . . . . . . . . . . . . . .1. . . . .2. . . . . . . . . . . . .4 Event Source . . . 9. . . . . . . . . . . . . . . . . . . . .1. Copyright c July 1999 Lee Chuk Munn. . . .1 The Serializable Interface . Listener and Event Objects 7.2 readObject and writeObject Method . . . . . . . . . . . . . 7. . . . 7. . . . . . . . .. . .1. . . iv . .2. . . 8. . 8. . . .2.3.5 Declaring Exceptions . . . .2.6 A Button Example . . . . . . . . . . .2 ObjectInputStream and ObjectOutputStream 10. . . . . . . . 10. . . . .2 The AccountEvent Object . . . . . .1. . . . . . . . . . . . . . 7. . 8. . . . . . . . .3. . . . . . . . . 10.1. .2. . . . . . . . 8. . . . . . . . . . . . . . . .1 Specifying What Gets Serialized . . 9.3 A File Copy Example . . . . . . 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.6 Generating Exceptions . . . . . . .3. . . . . . . 8. 7. . . . . . . . . . . . . . . . . . . . . . .1 Exceptions . . . . . . . . 9.1 InputStream . . . . .3 Stream Chaining . . . 7. . . 9. . . . . . . . . . . . . . . . . . . .1 Decorator Design .2. . . 10. . . .2. . . . . . . . . . . . . . . . . . . . . . . . . . . .3 Validating a Deserialized Object . . . . .1 The File Class . . . . . . . . . . . . . . . . . . . . . . .3. 7. . . . . . . . 7. . . . . .2. 7. . . . . . 8. . . . . . . .2. .1 An Exceptional Example 8. . . . . . All rights reserved. . . . .1. . . . . .4 Versioning . . . 9. . . . . .2. . . . . . . .2 Customizing the Serialization Process . . . . .1 Serialization . . . . . . . . . . . . .2 Character and Byte Streams . .3 try-catch Block . . . .4 And finally. 10. . . . . . . . . . 7. . . . . .2 Exception Objects . . . . . .1 Account Class Again . . . . . . . . . . . . . . . . 9. . . . . . . .4 Event Listener Registration/Deregistration .7 Another Button Example . . . Creating Customized Events . . . . . . . . . . . . . . . . .CONTENTS 7. . . . . .2 Performing I/O with Account . . . . 10. .3 AccountListener Interface . . .1. . . . . .2. . . . . . . . . 9 Streams 9. . . . . . . . . . . . . . . . . . . . . . . . . . . .1. . . . . . . . . . . .

. . . .1. . . . . . . . . . . . . . .java . . . . . . . . . . . .java . . . . . . . . . . . . . . . . . . . . . . . .1. 11. . . . . All rights reserved.3 AccountProtocol. .1 What is a Thread? . . . . . . . . . . . . . .1. . . . . .1. . . .3 Account Server . . . . . . . . . . . . . .2 Enhancing AccountServer . . . . . A. . . . . . .java . . . . . . . . . .2 Thread Safe Objects . . . . . . . . . . . . . . . . . . . . A.6 OverDrawnException. . A.2 Subclass and Implementations . . . . . A. . . . . . . . . .java . . . . . . . . . . . A. . . . . . . . A. . . . . .5 ErroneousAmountException. . . . . . . . . .2 SavingAccount.4 Counter. . . . . . . . .1 Account. .5 Implication of static on Threads . . . . . 12. . . .4 TightRate. .2 AccountListener. . . . . . . . . . . . .java . . . . . . A. . . .2. . . .2 ConnectionHandler. . .java . .1 FixedDepositAccount. . A. . . . . . . . . . . . . . . . .6 AccountServerAPI. .2.2. . . . . .4 Using the AccountServerAPI 12 Threads and Synchronization 12. . . . . . . . . . . . 12. .java . . . . . . .2. . .2. . . . . . . . . . . . . . . . . .3. .java . . . . A. . A. . . . . . . A. . A. 12. . . . . . . 125 . . . . . . . .2 Writing a Server . . . . . . . . . . .3. . . . . . 12. . . . . .4 States of a Thread . . . . .5 Counter. . .1 synchronized Keyword . . . . . . . . . . . . A. .3. . . . . .java .1. . . . . . . . . . . .java . . . . .java . . . . . . . . . . . . . . . . . . 12. . . . . . . . . .java . . . 120 . . . . 12.2. .java A. . .java . . . .2 Thread Class . . . . . . . .1 AccountServer. . . . . .2. . . . . 120 . . . . . .1. . .2. 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 . . . . . . . . . . . . A Listing A. . .3 AccountEvent. . . . . . . . . . . . . . . . . 12. . . . . . . . . . . A. 123 . . . . . . . . . . . . . . . . . . . . .1. . . . . . . . . A.3. . . . . . . . . .3. . .1 Defining the Protocol . . . . . .1. . . . . . . . . . . . . . . . . . . . . . A. . . . .4 AccountException. . .2. . . . A. 121 . . . . . . 11.java . . . . 11. . . . . . . . . . . . . . . . . . . . . . . . . . . . .2 Client-Server Model . .3. . . . . . . . . . . . . .3. . . . . . . . . . . . . . . . .1 Creating a Thread . . . . . . . . . . . 129 . . 12.java . . .3 Writing the Server API . .1 Core Classes . . . . . A. . . 12. . . . v . . . . . . . .java .4 Condition Variables . . 11. . . . .CONTENTS 11 Networking 11. . . . . . . 12.5 Interest. .3 Priorities .1 Addresses and Ports . .1. . . . . . . . . . Copyright c July 1999 Lee Chuk Munn.3. . . . . . . . . . .2. . . 11. . . . .3 Synchrnonization . . . . . . . . . . . .3 GenerousRate. . . .

. . . . . . . . . . . . . . . PrettyPanel with a button . . . .List of Figures 1. . . . InputStream class hierarchy . . . . . . . . . . . . . . . . . . 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. . . . . Concept of an interface . .1 3. . . . . . . . . . . . . . . . . .13 7. . . Container managed by FlowLayout .2 5. .10 5. . .3 7. . . . . .6 5. . . 119 vi . . .12 5. . Stream chaining example . . . . An example of a Frame with a MenuBar A menu with MenuItems . . The cat class hierarchy . .3 9. . . . . . .4 7. . . . . . .1 Graphical interface of serialver . . . . . .1 5. . A Checkbox component . . . . . . . . . . . . . .9 5. . . . . . . . . . . . . . . . . . . . . . . . . The model/view/controller architecture Event source and listeners . . . . . . . . . A TextField component . . . . . .2 security architecture . . . . . . . .11 5.4 5. . . . .3 4. . . . . . A typical GUI front end . . . . . . . . . . . A Java calculator . . . . . . . . . . . . . . . . . . . . . . . . . . . .2 3. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2 7. A List component . . . . . . . . GUI produced by AFrame. . .5 5. . .1 5. Contents of an AccountInputStream file . .7 5. . . . . A Choice component . . . . . . . . . . . . . . . . . Container managed by BorderLayout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . InputStream class hierarchy . . . . . . . . Environment settings . . .5 9. Notifying listeners . . . . . . . . . . . . . . . An example of using font . . . . . . . . . . . . . . . . . .4 The JDK 1. . . . . . . . . . .8 5. . . . . . . . . . . . .1 7. . . . . . .1 1. . . . . . . . . .1 9. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2 9. . . . . . . . . . . .java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A RolloverButton example . . . . Account class hierarchy . . . . .2 3. . . Instantiation . . . . . . . . . . . . . . . . . Container managed by GridLayout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3 5. . . . . . . . . . . . . . . . . . . . . .

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

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

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

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

tamper-free systems. The access controller is only found in JDK 1. All rights reserved. Copyright c July 1999 Lee Chuk Munn. Key database A database to store keys used by the security manager and access controller to verify the digital signature in signed class files. the security manager works in tandem with the access controller.2 security architecture Security has been further beefed up with the release of JDK 1. Security package The security package forms the basis of authenticating signed Java classes. 3 .6 construction of virus-free. Access controller The access controller allows or prevents access to the operating system. Class loader Loads classes that are not found in the CLASSPATH. In JDK 1.2. 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.Secure 1.2 security architecture (see figure 1.1. 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.1.2. The JDK 1. Core classes are not subjected to the bytecode verifier’s scrutinity.2. The JVM defines a “sandbox” where the user can safely and securely download and use Java classes.1: The JDK 1. Security manager The security manager is the primary interface between the core API and the operating system.

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

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

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

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

1 Reserved Word Java is a very small and compact language.3 on page 9). These types can be classified into the following groups: 1. represented as two’s complement 8 . 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. Integer.Chapter 2 The Java Programming Language 2. There following is a list of Java keywords.1: List of Java reserved words 2. These words are reserved any may not be used in any identifiers (see section 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.2 Primitive Types All data in Java belongs to a particular type.

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

valid • $12345.2 String Concatenation Strings can be concatenated using the plus operator (+). . 2.2: Binary operators 2. invalid To declare and use and identifier.4 Operators If you are familar with either C or C++ operators then you will feel right at home with Java operators.4. int foo.1 Binary Operators Binary operators take two operands and returns a result. 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.3 Unary Operator Unary operators changes the sign of a value or variable. Please refer to table 2. 2. 2. bar = 100.2.4 • toBeOrNotToBe.4.4. we have to preceed it with a type. valid • 123isAsEasyAsABC.Unary Operator 2. The code snippet below illustrates this. Lets declare an identifier called foo and bar which are of type integer (int). String msg = "There are " + days + "in a leap year. All rights reserved. We will also initialize bar with the value of 100.4.". 2 + -3 10 Copyright c July 1999 Lee Chuk Munn.

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

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

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

break.out. break. The break statements are necessary because case statements fall through. . break.println("October"). . The break statements cause control to break out of the switch and continue with the first statement following the switch. default: System. case 12: System.println("Not a valid month"). Copyright c July 1999 Lee Chuk Munn. . The default and break are optional. case 7: System.out. break. then an appropriate month will be printed otherwise a Not a valid month message will be printed. case <value_2>: <statement_2> .println("July"). case 10: System. .println("September").out. break.out.out.out.out.println("June"). case 8: System. .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. break.switch-case Statement 2. That is. 16 .out. break.5. break. The general syntax of the switch statement is as follows: switch <condition> case <value_1>: <statement_1> .println("December"). case 11: System.println("November"). The default acts as a catch all if month is not in the specified range. . . without an explicit break control will flow sequentially through subsequent case statements. } If month falls in the range of 1 and 12. All rights reserved. case 9: System. break.println("August").

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

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

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

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

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

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

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

a class definition has the following syntax: public class <class_name> { <member_declaration> <methods_declaration> } Classes can contain properties usually modelled by member variables.java”. 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. } public void transfer(Account from. account balance and overdraft as properties. 3.3. withdrawal() and transfer() method. float amt) { if (amt < 0) return. account number. In Java.withdrawal(amt).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. } public void withdrawal(float amt) { if ((amt <= balance) && (amt >= 0)) balance -= amt.3. from. public float balance. deposit(amt). These are also declared as part of the class body.Objects and Class 3. Account also has the deposit().1 3. } } Copyright c July 1999 Lee Chuk Munn.2.3 3. All rights reserved. The word polymorphism is a derived from two words: “poly” which means many and “morph” which means forms.2. public void deposit(float amt) { if (amt >= 0) balance += amt. Refering to figure 3. The following is an Account class with name. public int acctNo. public boolean overdraft.7 What is Polymorphism? Polymorphism is the ability of an object to assume many different forms. 26 . This class must by save in a file called “Account. 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.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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.Differences between Abstract Class and Interface 4. Static in the sense that it is compiled into a class. You can implement more than 1 interface. Interface You implements and interface. All rights reserved. 48 . You are allowed to selectively override any abstract methods.3 Abstract Class You extends an abstract class. Table 4. Can only subclass 1 abstract class. You must implement all the methods in it.

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

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

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

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

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

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

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

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

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

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

59 .add("Nike"). choice.add("Adidas").7: A Choice component The add() method adds an item item with the specified label to Choice. public void select(String str) Programatically selects an item from a Choice.add("Nike").4 Choice This class represents a drop down list.add("Reebok"). public void remove(String label) Removes an item. public int getItemCount() Returns the number of items in a Choice. All rights reserved. Other methods in Choice includes: public String getSelectedItem() Returns the label of the selected item.4.4. choice. 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.7. The following illustrates its use: 1 2 3 4 Choice choice = new Choice().5 5. true). 5. A Choice is shown in figure 5. The List is scrollable if necessary.4. choice. 1 2 3 4 List list = new List(4.add("Reebok").List 5. Copyright c July 1999 Lee Chuk Munn. Figure 5.5 List A List component is used to display a list of strings. list. list. list.add("Adidas").

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

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

we override this paint() method. 5. we must first understand the AWT paint cycle. The signature for paint() is as follows: public void paint(Graphics g) The Graphics parameter is an abstract representation of the screen. The components will redraw themselves again when either one of the following 2 events occurs: Exposure — This happens when we resize a frame.5 The AWT Paint Cycle We have seen how most of the components behave. In this case. 40).5. The key to customization lies in the following methods: paint(). 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. Recall that Component is the superclass of all components (widgets). Horizontal and vertical scrollbars will automatically appear when required. The following sequence of method cals occurs: repaint() −→ update() −→ paint() Copyright c July 1999 Lee Chuk Munn. 62 . Whatever we “draw” on Graphics will appear on the screen. All rights reserved.6 in page 63. The previously mentioned 3 methods are part of Component. these components draw themselves on the screen.5. update() and repaint(). 5. The program can call repaint() to force a redraw. 5. We invoke repaint() which schedules a cal to update(). the JVM will call the paint() method of each component in a Frame. When a component is first displayed.2 repaint() Method Sometimes we want to update a component on the window or the entire window all together. the JVM will call paint() directly.3 1 TextArea textArea = new TextArea(5. We will look at Graphics in section 5. 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.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. To customize a component. an animated button needs to draw the next image.repaint() Method 5.5.

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

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

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

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

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

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

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

public class DefaultRate implements Interest { public float calculate(float amt) { return (balance * 0. } . This is the member class. private float balance.1 • An instance of a member class must always be associated with an instance of its containing class. it will install a default interest calculation method.calculate(getBalance())). . 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. . . } } public Account(String n. including private methods and members. All rights reserved. . } The explanation for the above code is as follows: line 6 to 11. • A member class can access its methods and members as well as those of its containing class. .Member Class 6. • A user can install its own interest rate calculation method via the setInterestCalculation() method. . private Interest interest. 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. int no) { interest = new DefaultRate(). Our inner class is called DefaultRate and it implements the Interest interface. .1F). Notice that declaring a member class is just like defining a regular top level class. . 70 Copyright c July 1999 Lee Chuk Munn. } . public void setInterestCalculation(Interest i) { interest = i. } public float calculateInterest() { return (interest.

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

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

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

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

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

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

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

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

2.3 Event Listener Interface The event listener interface is an interface that contains methods denoting specific events. All rights reserved. These methods are called event handling methods.3 public void addActionListener(ActionListener l) public void removeActionListener(ActionListener l) • Action event listeners are those objects which implements the ActionListener interface.1: AWT event list 7.Event Listener Interface 7.2.1 show a list of all AWT events. 79 . 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. When Copyright c July 1999 Lee Chuk Munn. The table 7. • ActionEvent is the event object passed from the event source to the event listener.

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

event. line 5. Our specification is that when the mouse pointer leaves the button. Perform the necessary color change in the event handler methods. we are the source as well as the listener. 81 .awt. line 6.red). To capture AWT events.red). We register with RolloverButton that we are interested in receiving mouse events.awt. 3. public class RolloverButton extends Button implements MouseListener { public RolloverButton(String label) { super(label). the button returns to a black background and red foreground color pair. All rights reserved. Notice that we are adding ourself as a listener viz.*. We must implement MouseListner interface to capture mouse events.black).A Button Example 7. The listener must implement the MouseListener.2.black). 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. we fake a mouseExited() event to set the initial button behaviour. setForeground(Color. 4.event. mouseExited(null). } 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. you must import java. import java.awt. } public void mouseEntered(MouseEvent mEvt) { setBackground(Color.*. Here.*. import java. line 9. Copyright c July 1999 Lee Chuk Munn. Register the listener with the event source which in this case is the RolloverButton. setForeground(Color. line 10. We reuse Button class since RolloverButton is essentially a Button. addMouseListener(this). } public void mouseExited(MouseEvent mEvt) { setBackground(Color.6 2.lang.

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

} } 7. All rights reserved. • The event interface is call XXXListener according to the JDK naming conventions. Each method should return void and take one parameter. which is the event object. Remember.setVisible(true).3 Creating Customized Events How do we create and fire our own events? Short answer: not very difficult. • Define an interface that extends EventListener interface which is in package java. Define the event source This could be any class that is firing the event. 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. • The event class must be a subclass of EventObject which is found in package java. define an event firing method.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. Copyright c July 1999 Lee Chuk Munn. ex.3.1 19 20 21 22 ButtonEventEx ex = new ButtonEventEx(). • Every method in the listener interface denotes a specific event. Define the listener interface This is the interface that all listener must implement. • Call your event class XXXEvent according to the JDK naming conventions. • Add event registration and deregistration method. events in the JDK 1.util. 83 .Creating Customized Events 7. 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.util. The EventListener interface is a “marker” interface. An example of an event handler method is as below: public void someMethod(XXXEvent xEvt).

Notice that this is a read only property.*. float amt) { super(src). 7. line 6. The constructor takes 2 parameters. Getter for the amount properties.util package because the EventObject class is in it.util. The event object will have a read only property called amount which gives the amount deposited or withdrawn.3 AccountListener Interface The AccountListener interface contains event handling methods that will be called when a specific event occurs. } public float getAmount() { return (amount).3. amount = amt. Calls the superclass’ constructor and sets the event source.AccountListener Interface 7.lang. All rights reserved. This is because event objects are considered immutable so there are no setter methods. public AccountEvent(Object src.3.3. line 7.2 The AccountEvent Object Information pertaining to a particular transction in Account is encapsulated in the AccountEvent an event object. 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. 84 .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. import java. line 10 to 12.3 7. The event will contain the amount deposited or withdrawn. Remember to import java.3. 7. The code for AccountEvent is as follows: 1 2 3 4 5 6 7 8 9 10 11 12 13 import java. src is the event source and amt is the amount deposited or withdrawn. } } The explanation is as follows: line 2. public class AccountEvent extends EventObject { private float amount.*.

} 7. fireMoneyDeposited(new AccountEvent(this.*. . public abstract class Account { private String name.3. 85 . must provide registration and deregistration method.Event Listener Registration/Deregistration 7. listeners = new Vector(). 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. public interface AccountListener extends EventListener { public void moneyDeposited(AccountEvent aEvt). private float balance. .util. private Interest interest. int no) { . The event source class. . import java.lang. the event listeners have to register themseleves the the event source. Account in this case. .*. import java.*. So the AccountListener interface looks like this: 1 2 3 4 5 6 7 import java. private Vector listeners. A class that wants to handle any of the events defined in the AccountListener interface should implement that interface. public void moneyWithdrawn(AccountEvent aEvt). } } public void withdrawal(float amt) { if ((amt <= balance) && (amt >= 0)) { Copyright c July 1999 Lee Chuk Munn. All rights reserved. amt)). public Account(String n. .4 EventListener.4 Event Listener Registration/Deregistration Inorder for listeners to be notified of potential events.lang.*.3.util. } public void deposit(float amt) { if (amt >= 0) { balance += amt.

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

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

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) { . All rights reserved.. } } Figure 7. } public void moneyWithdrawn(AccountEvent aEvt) { .5: Notifying listeners Copyright c July 1999 Lee Chuk Munn..3.Event Listener Registration/Deregistration 7...

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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. line 4.Chapter 10 Object Serialization Streams I/O has traditionally been used to save and retrieve “record” type data. including its super class if any. in fact you will have to save all super classes. 112 . only members of the object is serialized. 10. } Consider the following points from ComplexObject class above: line 2. 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 are not serialized. . static and final members. stream I/O may well be adequate but for “complex” objects. private int index. 1 2 3 4 5 6 7 8 public class ComplexObject extends SuperComplexObject { public String name. You will also have to save someObject. If there are no getter methods for index. writing a filter stream may not be as straight forward. When an object is serialized. // methods and constructors . This is sometimes also known as persistence. how are you going to save this? line 5. .

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

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

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

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

3 public voiid validateObject() throws InvalidObjectException. . . Implement ObjectInputValidation in you class. .defaultWriteObject(). write your validation code in validateObject(). Copyright c July 1999 Lee Chuk Munn.readLong().getTime()/1000)/60)/60)/24). if ((current .writeLong(((((new Date()). private transient Interest interest. line 7. private transient long serTime. 2. 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. serTime is a temporary variable for holding the serialized time. ClassNotFoundException { in. in. 117 . out. . ObjectInputValidation { private String name. See line 18. public Account() { } . 0).defaultReadObject(). All rights reserved.Validating a Deserialized Object 10. . Lets rewrite the Account validation using this framework. private void writeObject(ObjectOutputStream out) throws IOException { out. You have to implement the ObjectInputValidation interface. } . . To use ObjectInputValidation you must perform the following steps: 1. private boolean overdraft. } public void validateObject() throws InvalidObjectException { long current = ((((new Date()). } private void readObject(ObjectInputStream in) throws IOException.registerValidation(this.serTime) > 60) throw new InvalidObjectException("Object expired!").getTime()/1000)/60)/60)/24. The explanation for the above code is as follows: line 2. . serTime = in. Register your validation interface in readObject() method using registerValidation().

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

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.1. You can examine a class’s serialVersionUID with serialver in the bin directory of the JDK. To view a class’ version number. 119 . JDK will compute1 a version number using the signature of a stream of bytes that reflect the class definition. Figure 10. All rights reserved. This will not happen if you explicitly provide a serialVersionUID.Versioning 10. An example is shown in figure 10. The danger here is that the serialVersionUID will change whenever you modify the class. run the following command serialver -show and type the class’ name in the “Full Class Name:” window.4 If you did not provide a serialVersionUID.

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

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

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

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

getAccountNumber(). } public int getCommand() { return (cmd). } } Lets examine the code: line 2. 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. int id) { cmd = c. public int getAccountNumber() Returns the contained account number.2. private final int cmd. we have to pass one of these objects from the client to server and vice versa. } public int getAccountNumber() { return (accountId). public Account getAccount() Returns the Account object contained within the AccountProtocol. private final int accountId. Remember. private final Account account. public AccountProtocol(int c. } public AccountProtocol(int c. public static final int GET = 0. public static final int PUT = 1. accountId = id. account = null. The Serializable interface ensure that AccountProtocol is writable across the network. Copyright c July 1999 Lee Chuk Munn. public static final int OKAY = 2. } public Account getAccount() { return (account). account = acct.Defining the Protocol 11. 124 .1 public int getCommand() Returns the command of the protocol. All rights reserved. Account acct) { cmd = c. accountId = acct.

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

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

Writing a Server 11. ObjectOutputStream oos = new ObjectOutputStream( clnt.writeObject(new AccountProtocol( AccountProtocol.*.println("AccountServer started.*.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.PUT: handlePut(oos.io.getInputStream()). oos.close().readObject().ERROR.GET: handleGet(oos.net. while (true) { try { Socket clnt = accept(). 127 . public class AccountServer extends ServerSocket { public static final int PORT = 12345. AccountProtocol acctProto = (AccountProtocol)ois. clnt. break.2. } finally { ois.. break. case AccountProtocol. import java."). case AccountProtocol. import java. } } catch (Exception e) { } } } private void handleGet(ObjectOutputStream netOOS Copyright c July 1999 Lee Chuk Munn.lang. ObjectInputStream ois = new ObjectInputStream( clnt. public AccountServer(int port) throws IOException { super(port).. acctProto).close(). All rights reserved. try { switch (acctProto. } public void run() { System.getCommand()) { case AccountProtocol.getOutputStream()).close().*. acctProto). 0)).out.

} private void handlePut(ObjectOutputStream netOOS . oos. (Account)ois.readObject()). netOOS. 0)).OKAY. oos.getAccountNumber() + ". we wait for client connection and process them.writeObject(new AccountProtocol(AccountProtocol. We manually chain the super class’ constructor because ServerSocket does not have a construct with the default constructor’s signature. netOOS. The AccountServer is a subclass of ServerSocket. line 5.ser"). } public static void main(String[] args) throws Exception { AccountServer server = new AccountServer(PORT).writeObject(result). oos.run().2. it will return with a Socket instance when a client connects.flush(). We do not have to create a separate ServerSocket just to accept client connection.Writing a Server 11.net package. Copyright c July 1999 Lee Chuk Munn. accept() waits for a connection. netOOS. In here. line 15. server. ObjectInputStream ois = new ObjectInputStream(fis).getAccount()).writeObject(proto. AccountProtocol proto) throws Exception { FileOutputStream fos = new FileOutputStream( proto. All rights reserved. AccountProtocol proto) throws Exception { FileInputStream fis = new FileInputStream( proto.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 . AccountProtocol result = new AccountProtocol( AccountProtocol. 128 .flush(). } } Explanation for the AccountServer code is as follows: line 3. ois. line 9.close().ser"). ObjectOutputStream oos = new ObjectOutputStream(fos). netOOS.flush().OKAY .close(). The run() method is our main loop. line 11 to 41. Remember to import java.getAccountNumber() + ".

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

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

oos = new ObjectOutputStream(toServer. Copyright c July 1999 Lee Chuk Munn. else return (null). } } private void connect() throws APIException { try { toServer = new Socket(hostname. } try { close().getAccount()). oos.2. connect(). ois = new ObjectInputStream(toServer. else return (null). } public Account putAccount(Account acct) throws APIException { AccountProtocol result = write( new AccountProtocol(AccountProtocol.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. } finally { return (result).getOutputStream()). All rights reserved. acctId)).OKAY) return (result. if (result.GET.getInputStream()). } public Account getAccount(int acctId) throws APIException { AccountProtocol result = write( new AccountProtocol(AccountProtocol.getCommand() == AccountProtocol. AccountServer.Writing the Server API 11. result = (AccountProtocol)ois.getCommand() == AccountProtocol. throw new APIException(e.flush().writeObject(proto). try { oos. } public AccountProtocol write(AccountProtocol proto) throws APIException { AccountProtocol result = null.PUT. acct)). } catch (Exception e) { close().PORT).getMessage()).OKAY) return (acct). if (result. 131 .readObject().

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

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

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

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

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

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

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

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

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

} public void run() { try { ois = new ObjectInputStream(clnt.getCommand()) { case AccountProtocol. .readObject(). break. } } private void handleGet(ObjectOutputStream netOOS .getOutputStream()). oos = new ObjectOutputStream(clnt. AccountProtocol acctProto = (AccountProtocol)ois.PUT: handlePut(oos. acctProto). case AccountProtocol. public ConnectionHandler(Socket sock) throws IOException { clnt = sock. private Socket clnt.ERROR: default: } } catch (Exception e) { oos. case AccountProtocol. private ObjectOutputStream oos.close(). } finally { ois.getMessage()). .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. clnt.flush(). acctProto). } } catch (Exception e) { System.out. 0)).close().1. break. oos. oos.GET: handleGet(oos.writeObject(new AccountProtocol( AccountProtocol. 141 .getInputStream()). All rights reserved.ERROR.println(e. AccountProtocol proto) throws Exception { // as before .close().Thread Class 12. } Copyright c July 1999 Lee Chuk Munn. try { switch (acctProto.

.println(e.out.io. import java.println("AccountServer started. 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. while (true) { try { Thread thread = new Thread( new ConnectionHandler(accept())). .*. Most of the “multi threading” logic is between between lines 15 to 17.1. thread.*.. public class AccountServer extends ServerSocket { public static final int PORT = 12345.getMessage()). it creates a ConnectionHandler to handle the client."). } } } public static void main(String[] args) throws Exception { AccountServer server = new AccountServer(PORT). When the server receives a client connection.run(). The bulk of the code which was previously in a while loop is now in a run() method (line 13 to 42 ).out. Copyright c July 1999 Lee Chuk Munn. } public void run() { System. } } Notice how simple AccontServer has become. import java.2 49 50 51 52 53 54 55 private void handlePut(ObjectOutputStream netOOS . } } If you examine the ConnectionHandler class you would have notice that all the the code is exactly from AccountServer.lang.start().. } catch (Exception e) { System. AccountProtocol proto) throws Exception { // as before .*. 142 . public AccountServer(int port) throws IOException { super(port).net.Thread Class 12. All rights reserved. server.

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

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

2 5. All rights reserved. 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. public boolean containsKey(Object key) Test if the hashtable contains key. Object data) Associate the key with data.Enhancing AccountServer 12. We will use the following 3 methods from Hashtable: public Object put(Object key. This class implements a hashtable. otherwise the corresponding data is returned. hashtable is a structure that allows you to store data by associating the data with a unique key. Will return null if the key is not in the hashtable. public Object remove(Object key) Deletes the key from the hashtable. we employ Hashtable class. 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 . the previous will be returned and the current data data will take its place.3. Copyright c July 1999 Lee Chuk Munn. Briefly.3: A modifed flow diagram of AccountServer’s protocol To implement the checkout list. The modified protocol is shown in figure 12. If the key exists in the hashtable.

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

checkout = table.RELEASE: handleRelease(oos. . import java. break. Copyright c July 1999 Lee Chuk Munn. private Socket clnt. Hashtable class is in java. .io. } } catch (Exception e) { .*.getCommand()) { . AccountProtocol acctProto = (AccountProtocol)ois. . Everything else in AccountServer remains save for those modifications listed above. . we now need to pass to the thread checkout. the listing for ConnectionHandler. acctProto).2 line 4. private Hashtable checkout.util. line 12.readObject(). try { switch (acctProto. case AccountProtocol. A instance of Hashtable is shared by all ConnectionHandler threads. } public void run() { try { ois = new ObjectInputStream(clnt. When we create a thread. import java. 147 . import java. .*. All rights reserved.getOutputStream()).getInputStream()). 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.Enhancing AccountServer 12.*. oos = new ObjectOutputStream(clnt.util package. line 19. public ConnectionHandler(Socket sock. . Instantiate checkout when we create the server.net. Hashtable table) throws IOException { clnt = sock. . line 8. public class ConnectionHandler implements Runnable { private ObjectInputStream ois. The thread will check if a given account is in checkout.*. private ObjectOutputStream oos.lang. We declare checkout as a Hashtable. And finally.

} else { FileInputStream fis = new FileInputStream(key + ". } private void handleRelease(ObjectOutputStream netOOS . netOOS. } 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 . All rights reserved.remove(key). oos. AccountProtocol proto) throws Exception { AccountProtocol result. 0). ObjectInputStream ois = new ObjectInputStream(fis).flush(). handleRelease(netOOS.Enhancing AccountServer 12. if (checkout.containsKey(new Integer(key))) { result = new AccountProtocol(AccountProtocol.writeObject(result).OKAY. ois. AccountProtocol proto) throws Exception { FileOutputStream fos = new FileOutputStream( proto. netOOS. oos. The explanation for the modified ConnectionHandler is as follows: Copyright c July 1999 Lee Chuk Munn. } public static void main(String[] args) { .getAccountNumber()). . 0)).flush().put(key.getAccountNumber() + ". Account account = (Account)ois.writeObject(new AccountProtocol( AccountProtocol.readObject(). account). AccountProtocol proto) { Integer key = new Integer(proto. 148 . checkout.ser").ser"). result = new AccountProtocol( AccountProtocol.getAccountNumber()). ObjectOutputStream oos = new ObjectOutputStream(fos).writeObject(proto.containsKey(key)) checkout. account).getAccount()). proto).close(). } private void handlePut(ObjectOutputStream netOOS .OKAY. .flush(). oos.close(). netOOS.INUSE. Integer key = new Integer(proto. if (checkout.

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

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

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

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

flush().flush().getAccountNumber() + ". netOOS. } } line 11 to 24.writeObject(proto. handleRelease(netOOS. oos.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 + ".put(key.close(). netOOS.writeObject(result).getAccount()). This synchronized block (critical region) ensures that deserialization and updating of checkout is atomic. Note that we have changed nothing in the original code save for enclosing it with a synchronized. oos.close(). 153 .getAccountNumber()). result = new AccountProtocol(AccountProtocol. ObjectOutputStream oos = new ObjectOutputStream(fos).OKAY . Copyright c July 1999 Lee Chuk Munn. All rights reserved. } netOOS.readObject().OKAY . AccountProtocol proto) throws Exception { Integer key = new Integer(proto. checkout. ois. } } netOOS.writeObject(new AccountProtocol(AccountProtocol. ObjectInputStream ois = new ObjectInputStream(fis). oos. AccountProtocol proto) throws Exception { synchronized(checkout) { FileOutputStream fos = new FileOutputStream( proto.ser"). account).flush().remove(key). synchronized(checkout) { if (checkout.3. Account account = (Account)ois. 0)). account).containsKey(key)) checkout.ser"). proto). } } private void handleRelease(ObjectOutputStream netOOS .synchronized Keyword 12. } private void handlePut(ObjectOutputStream netOOS .

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

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

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

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

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

All rights reserved. Both the above method will throw IllegalMonitorStateException if the caller is not the current owner of the lock. viz. After a thread is awakened. } public synchronized void add() { if (current == maximum) while (true) try { wait(). When wait() is called. notify(). The caller of this method must first acquire the lock. the thread releases its lock on an object and waits until another thread notifies it to wake up through notify(). then we wait until we are notified. } public int getCount() { return (maximum).Condition Variables 12. break. 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. calling from within a synchronized block. it must reacquire the lock before it can proceed. private int current. public Counter(int max) { maximum = max. public void notify() This method wakes up a thread that has called wait(). This method can only be called by the current owner of the lock. } public synchronized void release() { current = (--current < 0)? 0: current. } } line 13. If we have already reached maximum. notify() arbitrarily awakens just 1 thread.4 to wait until it is notified by another thread to stop waiting. } catch (InterruptedException e) { } current++. current = 0. 159 .

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

} 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(). All rights reserved. Figure 12. flintstone. Calls add(). mercury. Calls release(). Wakes up.age = 45. Release lock on exit. mercury.age = 40. By making age Copyright c July 1999 Lee Chuk Munn. To achieve this behaviour. Release lock and go to sleep. Cannot proceed. changing a member variable cause all other instances to “see” this change.name = "Mercury". Acquire Counter’s lock. Tries to get Counter’s lock. thr2 Acquire Counter’s lock. flintstone. Continues running. we might want all instances to share a single member viz. This is because of the static declaration on age. Got Counter’s lock. release() calls notify(). Continues running. we preceed a member’s declaration with static. Sometimes. Consider the following simple declaration: 1 2 3 4 public class Fred { public String name. Releases Counter’s lock. Calls add().Implication of static on Threads 12. 161 . Fred mercury = new Fred().5 thr1 Acquire Counter’s lock. it will not affect the name of another instance. 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". Calls wait(). Exits release().5: wait() and notify() interaction change the name member of one instance via setName(). public static int age.

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

The listing is base on ideas that we have developed until chapter 12. private Interest interest.io. public abstract class Account implements Serializable { public static final long serialVersionUID = 1234567890L. A. A.*. private Vector listeners.1 Core Classes The following listing pertains to the core Account class.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. 163 . private float balance. int no) { name = n.*.lang. private boolean overdraft.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. acctNo = no. private int acctNo. public class DefaultRate implements Interest { public float calculate(float amt) { return (balance * 0.util. overdraft = false.1F).1. balance = 100F. private String name.java import java.*. import java. listeners = new Vector(). import java. } } public Account() { } public Account(String n.

MONTH)]. } public void setName(String n) { name = n. 0.1F.java A.1F. } public int getAccountNumber() { return (acctNo). } }.1F. if (amt >= 0) balance += amt. } public void withdrawal(float amt) throws OverdrawnException. fireMoneyDeposited(new AccountEvent(this.1. 0. if (amt < 0) throw new ErroneousAmountException("withdraw". 0. amt).0F}.12F. 0. 0.Account.08F. All rights reserved. 164 . } public boolean isOverdraft() { return (overdraft). this. 0. amt)). private float rate. } public void setOverdraft(boolean b) { overdraft = b. { rate = monthlyRate[ (Calendar.1F. ErroneousAmountException { if (amt > balance) throw new OverdrawnException("withdraw".1F.} public float calculate(float amt) { return (balance * rate).getInstance()).get(Calendar. } public void deposit(float amt) throws ErroneousAmountException { if (amt < 0) throw new ErroneousAmountException("deposit".07F. } public float getBalance() { return (balance). balance -= amt.1F. else return (0F). 0. public void setInterestCalculation(Interest i) { interest = i. amt). } public String getName() { return (name). } public abstract void printAccount(). } public float calculateInterest() { if (interest != null) return (interest. this. 0. 0.calculate(getBalance())). Copyright c July 1999 Lee Chuk Munn. amt).1F . 0. 0.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. this.

readLong()) > 60) throw new IOException("Object expired!"). out.withdrawal(amt). } private void writeObject(ObjectOutputStream out) throws IOException { out.clone(). 165 .defaultWriteObject(). } for (int i = 0. float amt) throws OverdrawnException. } for (int i = 0.moneyDeposited(aEvt).java A.Account. i < tmpV. } public void removeAccountListner(AccountListener l) { listeners.getTime()/1000)/60)/60)/24. } } public String toString() { return ("name = " + name + "\n" + "acctNo = " + acctNo + "\n" + "balance = " + balance + "\n" + "overdraft = " + overdraft + "\n"). deposit(amt). i++) { AccountListener l = (AccountListener)tmpV.in. l. amt)). } } private void fireMoneyWithdrawn(AccountEvent aEvt) { Vector tmpV. } } Copyright c July 1999 Lee Chuk Munn. from. } public void transfer(Account from.1.elementAt(i).defaultReadObject(). i < tmpV.writeLong(((((new Date()). All rights reserved.clone(). } private void readObject(ObjectInputStream in) throws IOException.moneyWithdrawn(aEvt). ErroneousAmountException { if (amt < 0) return.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. if ((current . ClassNotFoundException { in.size(). l. i++) { AccountListener l = (AccountListener)tmpV.elementAt(i).size(). synchronized(listeners) { tmpV = (Vector)listeners.removeElement(l).getTime()/1000)/60)/60)/24). long current = ((((new Date()). } private void fireMoneyDeposited(AccountEvent aEvt) { Vector tmpV. synchronized(listeners) { tmpV = (Vector)listeners. } public void addAccountListener(AccountListener l) { listeners.addElement(l).

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

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

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

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

} public Account getAccount() { return (account).4 89 90 91 92 93 } netOOS.getAccountNumber().*.3.writeObject(new AccountProtocol(AccountProtocol.*. public static final int PUT = 1.Counter. accountId = a. account = null.lang. } public int getAccountNumber() { return (accountId). private final int accountId. private final Account account. Copyright c July 1999 Lee Chuk Munn.java import java.OKAY. public static final int GET = 0. import java. private int current. Account a) { cmd = c. public class Counter extends Object { private final int maximum. All rights reserved.lang. private final int cmd. } } A. netOOS. public static final int RELEASE = 4.4 1 2 3 4 5 6 7 Counter. public static final int INUSE = 3. } public int getCommand() { return (cmd). public static final int OKAY = 2.*.java import java. accountId = a.3. } } A. public Counter(int max) { maximum = max. 0)).flush().java A. account = a. } public AccountProtocol(int c.3. public AccountProtocol(int c.io.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. int a) { cmd = c. 172 . public class AccountProtocol implements Serializable { public static final int ERROR = -1.

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

throw new APIException(e.writeObject(proto).readObject(). } finally { return (result). } catch (Exception e) { close(). } } public boolean isInUse() { return (inuse). else return (null). } catch (IOException e) { throw new APIException(e. oos. oos = new ObjectOutputStream(toServer.RELEASE. else return (null).java A. if (result.AccountServerAPI.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. inuse = AccountProtocol. if (result. try { oos.GET.getInputStream()).INUSE == result. } private void connect() throws APIException { try { toServer = new Socket(hostname.3. ois = new ObjectInputStream(toServer.getMessage()). connect().getCommand().PORT). AccountServer. 174 . } public void releaseAccount(int acctId) throws APIException { write(new AccountProtocol(AccountProtocol.flush(). result = (AccountProtocol)ois.getOutputStream()). acctId)).OKAY) return (acct). All rights reserved.PUT. acctId)). acct)).OKAY) return (result. } try { close(). } catch (UnknownHostException e) { throw new APIException(e.getCommand() == AccountProtocol.getCommand() == AccountProtocol. } } private void close() Copyright c July 1999 Lee Chuk Munn.getMessage()). } public Account putAccount(Account acct) throws APIException { AccountProtocol result = write( new AccountProtocol(AccountProtocol.getMessage()). } public AccountProtocol write(AccountProtocol proto) throws APIException { AccountProtocol result = null.getAccount()).

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

Sign up to vote on this title
UsefulNot useful