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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Method and Member Visibility

3.3.4

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

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

3.3.4

Method and Member Visibility

Encapsulation hides a class internal details for the outside world; if we were to provide getter and setter methods but leave Account class member declaration as public as in page 3.3.1, then we leave our members exposed. This is because public allows virtually any one to access the member. By using private, we have effectively closed all members to the outside world. By doing this, we are enforcing encapsulation. Java provides the following visibility keywords which can be used on members or methods:
Copyright c July 1999 Lee Chuk Munn. All rights reserved.

30

Inheritance

3.3.5

public A method or member that is declared public is accessible from any class. protected A method or member that is declared protected is accessible only to its subclass and the class itself. We will examine the notion of subclass in section 3.3.5 on page 31. private A private method or member of a class is only accessible from within that class. Other classes including subclass cannot access this member or method. Table 3.1 summarizes the previous points: Keyword public protected private Self Yes Yes Yes Subclass Yes Yes No Others Yes No No

Table 3.1: Method and member accessibility The following are some tips on using visibility scopes. • There is no reason why you should declare any member as public unless performance is a big issue. You should always encapsulate members with public setter and getter methods. Standard methods that manipulate your class should be made public. • If you have written a class and you want to perhaps give control of your class’ members and methods to its subclass but not anyone else, then declare these as protected. • Declare your members and methods as private if they are used only within your class.

3.3.5

Inheritance
The syntax for

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

The parent class is also know as superclass and the child class is sometimes called a subclass. We will now reuse Account to define SavingAccount and FixedDepositAccount. We want FixedDeposit to have the following additional characteristics:
Copyright c July 1999 Lee Chuk Munn. All rights reserved.

31

Inheritance

3.3.5

FixedDeposit • term to denote the duration of the deposit. • interest is the interest rate for term. SavingAccount • Nothing special about this class. Just an “is-a” relationship. The following code snippet implements this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32

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

32

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

13: A menu with MenuItems 5.9 Figure 5. But our GUI is still deviod of life. All rights reserved. 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. For that we need to understand events which we will examine in the chapter 7.AWT Events 5.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

import java.io. int no) { name = n.1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 Account. } } public Account() { } public Account(String n.1 Core Classes The following listing pertains to the core Account class. listeners = new Vector().*. private Vector listeners. A.1. balance = 100F.*. private boolean overdraft. 163 . acctNo = no.lang. private int acctNo. public abstract class Account implements Serializable { public static final long serialVersionUID = 1234567890L.util.*. private String name. overdraft = false. public class DefaultRate implements Interest { public float calculate(float amt) { return (balance * 0.1F). import java. private Interest interest. The listing is base on ideas that we have developed until chapter 12. A. private float balance.java import java.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.

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

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

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

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

} public void withdrawal() throws OverdrawnException.2.println("Account name = " + getName()). public class TightRate implements Interest { public float calculate(float amt) { Copyright c July 1999 Lee Chuk Munn.java import java. } public void printAccount() { System.4 1 2 3 4 TightRate.println("Mature on = " + getTerm()).out. ErroneousAmountException { Date today = new Date().out. if (today.lang.java import java. } public void withdrawal(float amt) throws OverdrawnException.2. System.2.after(term)) super.out. public class SavingAccount extends Account { public SavingAccount(String n.5F). 168 .2 1 2 3 4 5 6 7 8 9 10 11 SavingAccount.TightRate. } public void printAccount() { System.out.println("Account name = " + getName()). acct).withdrawal(amt).java import java.java A.println("Amount deposited = $" + getBalance()).2. System.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. All rights reserved.println("Interest rate = " + getInterest() + "%"). } } A. System. } } A.3 1 2 3 4 5 6 7 GenerousRate. int acct) { super(n.*.out. ErroneousAmountException { withdrawal(getBalance()). System.*.lang.out.println("Current balance = $" + getBalance()). } } A.*.lang.

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

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

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

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

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

Sign up to vote on this title
UsefulNot useful