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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

79 .2. • ActionEvent is the event object passed from the event source to the event listener.2.Event Listener Interface 7.3 Event Listener Interface The event listener interface is an interface that contains methods denoting specific events. These methods are called event handling methods.1 show a list of all AWT 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.1: AWT event list 7. All rights reserved. The table 7. When Copyright c July 1999 Lee Chuk Munn.

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

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

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

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

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

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

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

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

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

8. public class ExceptionEx { public String[] msgs = {"bonjour". We will begin our exception discussion by learing how to glean useful information for exception stacks. we will end this chapter by creating our very own exceptions. "chou san". We will then proceed to looking at Java exception mechanism. 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. 89 .lang.*. • You can determine exactly who handles an error. Defensive programming assumes all codes to be erraneous and proceeds to inter spread error checks to normal code. 8. exception travel up the method call stack until it is handled by one of the method. An exception is an event thrown either by the JVM or by your code to indicate that an error has occured.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 Exceptions Java’s way of defensive programming is via the use of its exceptions mechanism. Exceptions has the following two benefits: • They allow you to separate error handling code from normal code. Sometimes you can spend more coding time on checking and handling errors than actually writing your program.1. Unhandle exception are captured and reported by the JVM.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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