A Programmer's Guide To Java® SE 8 Oracle Certified Associate (OCA) Programmer’s Java SCJP Certification Third Edition
A%20Programmer%E2%80%99s%20Guide%20to%20Java%20SCJP%20Certification%20Third%20Edition
A%20Programmer%E2%80%99s%20Guide%20to%20Java%20SCJP%20Certification%20Third%20Edition
User Manual:
Open the PDF directly: View PDF .
Page Count: 1089
A Programmer’s Guide to
Java™ SCJP Certification
Third Edition
This page intentionally left blank
A Programmer’s Guide to
Java™ SCJP Certification
A Comprehensive Primer
Third Edition
Khalid A. Mughal
Rolf W. Rasmussen
Upper Saddle River, New Jersey • Boston • Indianapolis • San Francisco
New York • Toronto • Montreal • London • Munich • Paris • Madrid
Capetown • Sidney • Tokyo • Singapore • Mexico City
Many of the designations used by manufacturers and sellers to distinguish their products
are claimed as trademarks. Where those designations appear in this book, and the publisher
was aware of a trademark claim, the designations have been printed with initial capital letters or in all capitals.
The authors and publisher have taken care in the preparation of this book, but make no
expressed or implied warranty of any kind and assume no responsibility for errors or omissions. No liability is assumed for incidental or consequential damages in connection with or
arising out of the use of the information or programs contained herein.
The publisher offers excellent discounts on this book when ordered in quantity for bulk purchases or special sales, which may include electronic versions and/or custom covers and
content particular to your business, training goals, marketing focus, and branding interests.
For more information, please contact:
U.S. Corporate and Government Sales
(800) 382-3419
corpsales@pearsontechgroup.com
For sales outside the United States please contact:
International Sales
international@pearson.com
Visit us on the Web: informit.com/aw
Library of Congress Cataloging-in-Publication Data
Mughal, Khalid Azim.
A programmer's guide to Java SCJP certification : a comprehensive primer / Khalid A.
Mughal, Rolf W. Rasmussen.—3rd ed.
p. cm.
Previously published under title: A programmer’s guide to Java certification.
Includes bibliographical references and index.
ISBN 0-321-55605-4 (pbk. : alk. paper)
1. Electronic data processing personnel--Certification. 2. Operating systems (Computers)—Examinations--Study guides. 3. Java (Computer program language)--Examinations-Study guides. I. Rasmussen, Rolf (Rolf W.) II. Mughal, Khalid Azim. Programmer’s guide
to Java certification. III. Title.
QA76.3.M846 2008
005.2'762--dc22
2008048822
Copyright © 2009 Pearson Education, Inc.
All rights reserved. Printed in the United States of America. This publication is protected by
copyright, and permission must be obtained from the publisher prior to any prohibited
reproduction, storage in a retrieval system, or transmission in any form or by any means,
electronic, mechanical, photocopying, recording, or likewise. For information regarding
permissions, write to:
ISBN-13: 978-0-321-55605-9
ISBN-10:
0-321-55605-4
Text printed in the United States on recycled paper at Courier in Stoughton, Massachusetts.
First printing, December 2008
To the loving memory of my mother, Zubaida Begum,
and my father, Mohammed Azim.
—K.A.M.
For Olivia E. Rasmussen and
Louise J. Dahlmo.
—R.W.R.
This page intentionally left blank
Contents Overview
Foreword
Preface
1 Basics of Java Programming
xxxv
xxxvii
1
2 Language Fundamentals
19
3 Declarations
39
4 Access Control
103
5 Operators and Expressions
159
6 Control Flow
203
7 Object-Oriented Programming
283
8 Nested Type Declarations
351
9 Object Lifetime
389
10 Fundamental Classes
423
11 Files and Streams
467
12 Localization, Pattern Matching and Formatting
531
13 Threads
613
14 Generics
661
vii
viii
CONTENTS
15 Collections and Maps
747
A Taking the SCJP 1.6 Exam
851
B Objectives for the SCJP 1.6 Exam
857
C Objectives for the SCJP 1.6 Upgrade Exam
863
D Annotated Answers to Review Questions
869
E Solutions to Programming Exercises
935
F Mock Exam
959
G Number Systems and Number Representation
Index
1005
1013
Contents
List of Figures
xxiii
List of Tables
xxvii
List of Examples
xxix
Foreword
xxxv
Preface
1 Basics of Java Programming
1.1
1.2
1.3
1.4
1.5
1.6
1.7
1.8
1.9
1.10
Introduction
Classes
Declaring Members: Fields and Methods
Objects
Class Instantiation, Reference Values, and References
Object Aliases
Instance Members
Invoking Methods
Static Members
Inheritance
Aggregation
Tenets of Java
Review Questions
Java Programs
Sample Java Application
Essential Elements of a Java Application
Compiling and Running an Application
Review Questions
Chapter Summary
Programming Exercise
xxxvii
1
2
2
3
4
4
6
6
7
7
10
12
13
13
15
15
15
16
17
18
18
ix
x
CONTENTS
2
Language Fundamentals
2.1
2.2
2.3
2.4
3
Basic Language Elements
Lexical Tokens
Identifiers
Keywords
Literals
Integer Literals
Floating-Point Literals
Boolean Literals
Character Literals
String Literals
White Spaces
Comments
Review Questions
Primitive Data Types
Integer Types
The char Type
The Floating-Point Types
The boolean Type
Review Questions
Variable Declarations
Declaring and Initializing Variables
Reference Variables
Initial Values for Variables
Default Values for Fields
Initializing Local Variables of Primitive Data Types
Initializing Local Reference Variables
Lifetime of Variables
Review Questions
Chapter Summary
Programming Exercise
Declarations
3.1
3.2
3.3
3.4
Class Declarations
JavaBeans Standard
Naming Patterns for Properties
Naming Patterns for the Event Model
Method Declarations
Statements
Instance Methods and the Object Reference this
Method Overloading
Constructors
The Default Constructor
Overloaded Constructors
Review Questions
19
20
20
20
20
21
22
22
23
23
25
25
26
27
28
28
29
29
30
31
31
31
32
33
33
34
35
35
36
37
37
39
40
41
41
42
44
45
45
47
48
49
51
52
CONTENTS
xi
3.5
3.6
3.7
3.8
3.9
Enumerated Types
Declaring Typesafe Enums
Using Typesafe Enums
Declaring Enum Constructors and Members
Implicit Static Methods for Enum Types
Inherited Methods from the Enum Class
Extending Enum Types: Constant-Specific Class Bodies
Declaring Typesafe Enums Revisited
Review Questions
Arrays
Declaring Array Variables
Constructing an Array
Initializing an Array
Using an Array
Anonymous Arrays
Multidimensional Arrays
Review Questions
Parameter Passing
Passing Primitive Data Values
Passing Reference Values
Passing Arrays
Array Elements as Actual Parameters
final Parameters
Variable Arity Methods
Calling a Varargs Method
Varargs and Non-Varargs Method Calls
The main() Method
Program Arguments
Review Questions
Chapter Summary
Programming Exercises
4 Access Control
4.1
4.2
4.3
4.4
4.5
4.6
Java Source File Structure
Packages
Defining Packages
Using Packages
Compiling Code into Packages
Running Code from Packages
Searching for Classes
The JAR Utility
System Properties
Review Questions
Scope Rules
Class Scope for Members
54
54
54
55
57
58
59
62
63
69
70
70
71
72
74
75
79
81
82
84
86
87
89
90
91
93
94
95
96
100
101
103
104
105
106
107
115
117
117
120
122
123
129
129
xii
CONTENTS
4.7
4.8
4.9
4.10
5
Block Scope for Local Variables
Accessibility Modifiers for Top-Level Type Declarations
Other Modifiers for Classes
abstract Classes
final Classes
Review Questions
Member Accessibility Modifiers
public Members
protected Members
Default Accessibility for Members
private Members
Review Questions
Other Modifiers for Members
static Members
final Members
abstract Methods
synchronized Methods
native Methods
transient Fields
volatile Fields
Review Questions
Chapter Summary
Programming Exercise
Operators and Expressions
5.1
5.2
5.3
5.4
5.5
Conversions
Widening and Narrowing Primitive Conversions
Widening and Narrowing Reference Conversions
Boxing and Unboxing Conversions
Other Conversions
Type Conversion Contexts
Assignment Context
Method Invocation Context
Casting Context of the Unary Type Cast Operator: (type)
Numeric Promotion Context
Precedence and Associativity Rules for Operators
Evaluation Order of Operands
Left-Hand Operand Evaluation First
Operand Evaluation before Operation Execution
Left to Right Evaluation of Argument Lists
The Simple Assignment Operator =
Assigning Primitive Values
Assigning References
Multiple Assignments
Type Conversions in Assignment Context
131
132
135
135
136
138
138
139
141
142
143
144
146
147
148
150
150
151
152
153
154
157
157
159
160
160
161
162
162
163
164
164
164
165
166
168
168
168
169
169
169
169
170
171
CONTENTS
xiii
5.6
5.7
5.8
5.9
5.10
5.11
5.12
5.13
5.14
5.15
Review Questions
Arithmetic Operators: *, /, %, +, Arithmetic Operator Precedence and Associativity
Evaluation Order in Arithmetic Expressions
Range of Numeric Values
Unary Arithmetic Operators: -, +
Multiplicative Binary Operators: *, /, %
Additive Binary Operators: +, Numeric Promotions in Arithmetic Expressions
Arithmetic Compound Assignment Operators: *=, /=, %=, +=, -=
Review Questions
The Binary String Concatenation Operator +
Variable Increment and Decrement Operators: ++, -The Increment Operator ++
The Decrement Operator -Review Questions
Boolean Expressions
Relational Operators: <, <=, >, >=
Equality
Primitive Data Value Equality: ==, !=
Object Reference Equality: ==, !=
Object Value Equality
Boolean Logical Operators: !, ^, &, |
Operand Evaluation for Boolean Logical Operators
Boolean Logical Compound Assignment Operators: &=, ^=, |=
Conditional Operators: &&, ||
Short-Circuit Evaluation
Review Questions
The Conditional Operator: ?:
Other Operators: new, [], instanceof
Chapter Summary
Programming Exercise
6 Control Flow
6.1
6.2
6.3
Overview of Control Flow Statements
Selection Statements
The Simple if Statement
The if-else Statement
The switch Statement
Review Questions
Iteration Statements
The while Statement
The do-while Statement
The for(;;) Statement
The for(:) Statement
173
174
174
174
175
177
178
180
180
182
184
185
186
187
187
188
190
190
191
191
192
193
194
195
195
196
197
199
201
201
202
202
203
204
204
204
205
207
212
216
217
217
218
220
xiv
CONTENTS
6.4
6.5
6.6
6.7
6.8
6.9
6.10
7
Transfer Statements
Labeled Statements
The break Statement
The continue Statement
The return Statement
Review Questions
Stack-Based Execution and Exception Propagation
Exception Types
The Exception Class
The RuntimeException Class
The Error Class
Checked and Unchecked Exceptions
Defining New Exceptions
Exception Handling: try, catch, and finally
The try Block
The catch Block
The finally Block
The throw Statement
The throws Clause
Review Questions
Assertions
The assert Statement and the AssertionError Class
Compiling Assertions
Runtime Enabling and Disabling of Assertions
Using Assertions
Review Questions
Chapter Summary
Programming Exercises
Object-Oriented Programming
7.1
7.2
7.3
7.4
7.5
Single Implementation Inheritance
Inheritance Hierarchy
Relationships: is-a and has-a
The Supertype-Subtype Relationship
Overriding Methods
Instance Method Overriding
Covariant return in Overriding Methods
Overriding vs. Overloading
Hiding Members
Field Hiding
Static Method Hiding
The Object Reference super
Review Questions
Chaining Constructors Using this() and super()
The this() Constructor Call
223
223
224
226
228
229
235
239
241
241
242
243
244
245
245
246
251
255
257
260
265
265
267
269
272
276
279
279
283
284
286
286
287
288
288
290
292
294
294
294
295
297
302
302
CONTENTS
xv
7.6
7.7
7.8
7.9
7.10
7.11
7.12
7.13
7.14
The super() Constructor Call
Review Questions
Interfaces
Defining Interfaces
Abstract Method Declarations
Implementing Interfaces
Extending Interfaces
Interface References
Constants in Interfaces
Review Questions
Arrays and Subtyping
Arrays and Subtype Covariance
Array Store Check
Reference Values and Conversions
Reference Value Assignment Conversions
Method Invocation Conversions Involving References
Overloaded Method Resolution
Reference Casting and the instanceof Operator
The Cast Operator
The instanceof Operator
Review Questions
Polymorphism and Dynamic Method Lookup
Inheritance Versus Aggregation
Basic Concepts in Object-Oriented Design
Encapsulation
Cohesion
Coupling
Review Questions
Chapter Summary
Programming Exercises
8 Nested Type Declarations
8.1
8.2
8.3
8.4
8.5
Overview of Nested Type Declarations
Static Member Types
Declaring and Using Static Member Types
Accessing Members in Enclosing Context
Non-Static Member Classes
Instantiating Non-Static Member Classes
Accessing Members in Enclosing Context
Review Questions
Local Classes
Accessing Declarations in Enclosing Context
Instantiating Local Classes
Anonymous Classes
Extending an Existing Class
305
308
309
310
310
312
313
314
314
315
317
317
319
319
320
323
324
327
327
328
332
340
342
345
345
346
346
347
349
349
351
352
355
355
357
359
360
362
367
371
372
374
377
377
xvi
CONTENTS
Implementing an Interface
Instantiating Anonymous Classes
Accessing Declarations in Enclosing Context
Review Questions
Chapter Summary
Programming Exercise
9
Object Lifetime
9.1
9.2
9.3
9.4
9.5
9.6
9.7
9.8
9.9
9.10
9.11
Garbage Collection
Reachable Objects
Facilitating Garbage Collection
Object Finalization
Finalizer Chaining
Invoking Garbage Collection Programmatically
Review Questions
Initializers
Field Initializer Expressions
Static Initializer Blocks
Instance Initializer Blocks
Constructing Initial Object State
Review Questions
Chapter Summary
10 Fundamental Classes
10.1
10.2
10.3
10.4
Overview of the java.lang Package
The Object Class
Review Questions
The Wrapper Classes
Common Wrapper Class Constructors
Common Wrapper Class Utility Methods
Numeric Wrapper Classes
The Character Class
The Boolean Class
Review Questions
The String Class
Immutability
Creating and Initializing Strings
The CharSequence Interface
Reading Characters from a String
Comparing Strings
Character Case in a String
Concatenation of Strings
Searching for Characters and Substrings
Extracting Substrings
Converting Primitive Values and Objects to Strings
379
380
380
382
386
386
389
390
390
392
396
397
398
401
406
406
410
413
416
420
422
423
424
424
428
428
429
430
433
436
437
437
439
439
439
442
443
445
446
446
448
449
450
CONTENTS
xvii
10.5
Formatting Values
Pattern Matching
Review Questions
The StringBuilder and the StringBuffer Classes
Thread-Safety
Mutability
Constructing String Builders
Reading and Changing Characters in String Builders
Constructing Strings from String Builders
Appending, Inserting, and Deleting Characters in String Builders
Controlling String Builder Capacity
Review Questions
Chapter Summary
Programming Exercises
11 Files and Streams
11.1
11.2
11.3
11.4
11.5
11.6
Input and Output
The File Class
Querying the File System
File or Directory Existence
File and Directory Permissions
Listing Directory Entries
Creating New Files and Directories
Renaming Files and Directories
Deleting Files and Directories
Byte Streams: Input Streams and Output Streams
File Streams
Filter Streams
Reading and Writing Binary Values
Review Questions
Character Streams: Readers and Writers
Print Writers
Writing Text Files
Reading Text Files
Using Buffered Writers
Using Buffered Readers
The Standard Input, Output, and Error Streams
Comparison of Byte Streams and Character Streams
The Console class
Review Questions
Object Serialization
The ObjectOutputStream Class
The ObjectInputStream Class
Customizing Object Serialization
Serialization and Inheritance
450
452
452
456
456
456
457
457
458
458
460
461
464
465
467
468
468
470
472
472
473
473
474
474
475
477
479
479
484
488
490
492
494
495
496
499
500
500
506
510
511
512
517
519
xviii
CONTENTS
Review Questions
Chapter Summary
Programming Exercise
12 Localization, Pattern Matching, and Formatting
12.1
12.2
12.3
12.4
12.5
12.6
12.7
The java.util.Locale Class
The java.util.Date Class
The java.util.Calendar Class
Static Factory Methods to Create a Calendar
Interoperability with the Date Class
Selected get and set Methods
Manipulating a Calendar
Comparing Calendars
The java.text.DateFormat Class
Static Factory Methods to Create a Date/Time Formatter
Formatting Dates
Parsing Strings to Date/Time
Managing the Calendar and the Number Formatter
The java.text.NumberFormat Class
Static Factory Methods to Create a Number Formatter
Formatting Numbers and Currency
Parsing Strings to Numbers
Specifying the Number of Digits
Review Questions
String Pattern Matching Using Regular Expressions
Regular Expression Fundamentals
Escaping Metacharacters
The java.util.regex.Pattern Class
The java.util.regex.Matcher Class
The java.util.Scanner Class
Review Questions
Formatting Values
Overview
Defining Format Specifiers
Conversion Categories and Formatting Conversions
Selected Format Exceptions
Using the format() Method
Review Questions
Chapter Summary
Programming Exercises
522
529
530
531
532
535
536
537
537
537
539
540
541
541
542
543
545
546
546
546
547
547
551
554
554
561
562
566
571
582
593
593
595
597
601
602
604
610
610
13 Threads
613
13.1
13.2
13.3
614
614
615
Multitasking
Overview of Threads
The Main Thread
CONTENTS
xix
13.4
13.5
13.6
Thread Creation
Implementing the Runnable Interface
Extending the Thread Class
Review Questions
Synchronization
Locks
Synchronized Methods
Synchronized Blocks
Review Questions
Thread Transitions
Thread States
Thread Priorities
Thread Scheduler
Running and Yielding
Sleeping and Waking Up
Waiting and Notifying
Joining
Blocking for I/O
Thread Termination
Deadlocks
Review Questions
Chapter Summary
Programming Exercises
14 Generics
14.1
14.2
14.3
14.4
14.5
14.6
Introducing Generics
Generic Types and Parameterized Types
Generic Types
Parameterized Types
Generic Interfaces
Extending Generic Types
Raw Types and Unchecked Warnings
Collections and Generics
Wildcards
The Subtype Covariance Problem with Parameterized Types
Wildcard Types
Subtype Covariance: ? extends Type
Subtype Contravariance: ? super Type
Subtype Bivariance: ?
Subtype Invariance: Type
Some Restrictions on Wildcard Types
Using References of Wildcard Parameterized Types
Generic Reference Assignment
Using Parameterized References to Call Set and Get Methods
Bounded Type Parameters
Multiple Bounds
615
616
619
622
626
626
627
629
631
634
634
638
638
639
640
640
647
649
650
651
653
658
659
661
662
663
663
665
666
668
670
672
673
673
675
675
676
677
677
677
678
679
680
684
686
xx
CONTENTS
14.7
14.8
14.9
14.10
14.11
14.12
14.13
Review Questions
Implementing a Simplified Generic Stack
Generic Methods and Constructors
Generic Method Declaration
Calling Generic Methods
Wildcard Capture
Capture Conversion
Flexibility with Wildcard Parameterized Types
Nested Wildcards
Wildcard Parameterized Types as Formal Parameters
Flexible Comparisons with Wildcards
Recursive Bounds
Type Erasure
Bridge Methods
Implications for Overloading and Overriding
Method Signature
Implications for Overloading
Implications for Overriding
Limitations and Restrictions on Generic Types
Reifiable Types
Implications for instanceof operator
Implications for Casting
Implications for Arrays
Implications for Varargs
Implications for Exception Handling
Implications for Nested Classes
Other Implications
Review Questions
Chapter Summary
Programming Exercises
15 Collections and Maps
15.1
15.2
15.3
Comparing Objects
The equals() Method
The hashCode() Method
The Comparable Interface
The Comparator Interface
Review Questions
The Java Collections Framework
Core Interfaces
Implementations
Collections
Basic Operations
Bulk Operations
Iterators
686
695
697
699
700
703
705
705
705
707
709
712
714
716
716
716
717
718
722
722
723
724
726
729
730
731
733
734
744
745
747
748
751
760
765
771
775
777
778
780
784
784
785
785
CONTENTS
xxi
Array Operations
Review Questions
15.4 Sets
The HashSet and LinkedHashSet Classes
15.5 The SortedSet and NavigableSet Interfaces
The SortedSet Interface
The NavigableSet Interface
The TreeSet Class
15.6 Lists
The ArrayList, LinkedList, and Vector Classes
15.7 Queues
The Queue Interface
The PriorityQueue and LinkedList Classes
The Deque Interface
The ArrayDeque and LinkedList Class
Review Questions
15.8 Maps
Basic Operations
Bulk Operations
Collection Views
15.9 Map Implementations
The HashMap, LinkedHashMap, and Hashtable Classes
15.10 The SortedMap and NavigableMap Interfaces
The SortedMap Interface
The NavigableMap Interface
The TreeMap Class
Review Questions
15.11 Working with Collections
Ordering Elements in Lists
Searching in Collections
Changing Elements in Collections
Sorting Arrays
Searching in Arrays
Creating List Views of Arrays
Miscellaneous Utility Methods in the Arrays Class
Review Questions
Chapter Summary
Programming Exercises
A
Taking the SCJP 1.6 Exam
A.1
A.2
Preparing for the Programmer Exam
Registering for the Exam
Obtaining an Exam Voucher
Signing Up for the Test
Contact Information
790
791
796
796
800
800
801
802
804
806
809
809
810
813
815
816
821
821
822
822
823
823
826
826
827
828
833
838
838
840
841
842
843
845
846
846
849
850
851
851
852
852
852
852
xxii
CONTENTS
A.3
A.4
A.5
B
After Taking the Exam
How the Examination Is Conducted
The Testing Locations
Utilizing the Allotted Time
The Exam Program
The Questions
Types of Questions Asked
Types of Answers Expected
Topics Covered by the Questions
Moving on to Other Java Technology Exams
Objectives for the SCJP 1.6 Exam
853
853
853
853
854
854
854
855
855
856
857
C Objectives for the SCJP 1.6 Upgrade Exam
863
D Annotated Answers to Review Questions
869
E Solutions to Programming Exercises
935
F Mock Exam
959
G
Number Systems and Number Representation
G.1
G.2
G.3
G.4
Number Systems
Binary, Octal, and Hexadecimal Number System
Converting Binary Numbers to Decimals
Converting Octal and Hexadecimal Numbers to Decimals
Relationship between Binary, Octal, and Hexadecimal Numbers
Converting Decimals
Converting Decimals to Binary Numbers
Converting Decimals to Octal and Hexadecimal Numbers
Representing Integers
Calculating 2’s Complement
Index
1005
1005
1005
1006
1007
1007
1008
1008
1009
1010
1011
1013
List of Figures
1.1
UML Notation
for Classes
Chapter
11
1.2 UML Notation for Objects
1.3 Aliases
1.4 Class Diagram Showing Static Members of a Class
1.5 Members of a Class
1.6 Class Diagram Depicting Inheritance Relationship
1.7 Class Diagram Depicting Aggregation
2.1
Primitive
Chapter
2 19Data Types in Java
3.1
The Event
Chapter
3 39Model
3.2 Array of Arrays
3.3 Parameter Passing: Primitive Data Values
3.4 Parameter Passing: Reference Values
3.5 Parameter Passing: Arrays
4.1
Java Source
Chapter
4 103File Structure
4.2 Package Hierarchy
4.3 File Hierarchy
4.4 Searching for Classes
4.5 Searching in JAR files
4.6 Block Scope
4.7 Public Accessibility
4.8 Protected Accessibility
4.9 Default Accessibility
4.10 Private Accessibility
5.1
Widening
Primitive Conversions
Chapter
5 159
5.2 Overflow and Underflow in Floating-point Arithmetic
5.3 Numeric Promotion in Arithmetic Expressions
6.1
Activity
Diagram for if Statements
Chapter
6 203
6.2 Activity Diagram for a switch Statement
6.3 Activity Diagram for the while Statement
6.4 Activity Diagram for the do-while Statement
6.5 Activity Diagram for the for Statement
6.6 Enhanced for Statement
6.7 Method Execution
3
5
6
8
9
10
12
28
43
78
84
85
87
104
105
116
118
121
132
141
142
143
144
160
176
181
205
208
217
218
219
221
237
xxiii
xxiv
LIST OF FIGURES
6.8 Exception Propagation
6.9 Partial Exception Inheritance Hierarchy
6.10 The try-catch-finally Construct
6.11 Exception Handling (Scenario 1)
6.12 Exception Handling (Scenario 2)
6.13 Exception Handling (Scenario 3)
6.14 Execution of the Simple assert Statement (with Assertions Enabled)
6.15 Package Hierarchy
7.1
Inheritance
Chapter
7 283Hierarchy
7.2 Inheritance Relations
7.3 Reference Type Hierarchy: Arrays and Subtype Covariance
7.4 Type Hierarchy to Illustrate Polymorphism
7.5 Implementing Data Structures by Inheritance and Aggregation
8.1
Static Member
Chapter
8 351 Classes and Interfaces
8.2 Outer Object with Associated Inner Objects
8.3 Nested Classes and Inheritance
8.4 Local Classes and Inheritance Hierarchy
9.1
Memory
Organization at Runtime
Chapter
9 389
10.1
Partial10
Inheritance
Hierarchy in the java.lang Package
Chapter
423
10.2 Converting Values Between Primitive, Wrapper, and String Types
11.1
Partial11
Byte
Stream Inheritance Hierarchies
Chapter
467
11.2 Stream Chaining for Reading and Writing Binary Values to a File
11.3 Partial Character Stream Inheritance Hierarchies
11.4 Setting up a PrintWriter to Write to a File
11.5 Setting up Readers to read Characters
11.6 Buffered Writers
11.7 Buffered Readers
11.8 Keyboard and Display as Console
11.9 Object Stream Chaining
13.1
Spawning
Threads Using a Runnable Object
Chapter
12 613
13
531
13.2 Spawning Threads—Extending the Thread Class
13.3 Thread States
13.4 Running and Yielding
13.5 Sleeping and Waking up
13.6 Waiting and Notifying
13.7 Thread Communication
13.8 Stack Users
13.9 Joining of Threads
13.10 Deadlock
14.1
Extending
Generic Types
Chapter
14 661
14.2 No Subtype Covariance for Parameterized Types
14.4 Partial Type Hierarchy for Node
14.3 Partial Type Hierarchy for Node
14.5 Partial Type Hierarchy for Selected Parameterized Types of Node
14.6 Flexible Comparisons with Wildcards
15.1
The Core
Interfaces
Chapter
15 747
238
240
246
248
249
250
266
271
287
314
318
340
342
358
362
366
374
392
424
429
476
481
489
493
494
496
497
501
511
616
620
635
639
640
641
642
643
648
652
668
674
676
676
678
709
778
LIST OF FIGURES
15.2
15.3
15.4
G.1
XXV
The Core Collection Interfaces and Their Implementations
The Core Map Interfaces and Their Implementations
Bulk Operations on Collections
Converting between Binary, Octal, and Hexadecimal
781
782
785
1008
This page intentionally left blank
List of Tables
Chapter 1 11.1
2.1
Chapter 2 19
2.2
2.3
2.4
2.5
2.6
2.7
2.8
2.9
2.10
2.11
2.12
2.13
2.14
3.1
Chapter 3 39
4.1
Chapter 4 103
4.2
4.3
4.4
4.5
5.1
Chapter 5 159
5.2
5.3
5.4
5.5
5.6
5.7
5.9
5.8
5.10
5.11
5.12
Terminology for Class Members
Keywords in Java
Reserved Literals in Java
Reserved Keywords not Currently in Use
Examples of Literals
Examples of Decimal, Octal, and Hexadecimal Literals
Examples of Character Literals
Escape Sequences
Examples of Escape Sequence \ddd
Range of Integer Values
Range of Character Values
Range of Floating-Point Values
Boolean Values
Summary of Primitive Data Types
Default Values
Parameter Passing By Value
Accessing Members within a Class
Summary of Accessibility Modifiers for Top-Level Types
Summary of Other Modifiers for Types
Summary of Accessibility Modifiers for Members
Summary of Other Modifiers for Members
Selected Conversion Contexts and Conversion Categories
Operator Summary
Examples of Truncated Values
Arithmetic Operators
Examples of Arithmetic Expression Evaluation
Arithmetic Compound Assignment Operators
Relational Operators
Reference Equality Operators
Primitive Data Value Equality Operators
Truth-Values for Boolean Logical Operators
Boolean Logical Compound Assignment Operators
Conditional Operators
10
21
21
21
21
22
23
24
25
28
29
29
30
30
33
82
130
135
137
144
153
163
167
172
174
180
183
191
192
192
195
196
196
xxvii
xxviii
LIST OF TABLES
5.13
6.1
Chapter 6 203
Chapter
Chapter
Chapter
Chapter
Chapter
Chapter
Chapter
6.2
6.3
7.1
7 283
7.2
8.1
8 351
9
1011.1
11
389
423
467
11.2
11.3
11.4
11.5
11.6
11.7
1212.1
531
12.2
12.3
12.4
12.5
12.6
12.7
12.8
12.9
12.10
12.11
12.12
12.13
12.14
12.15
12.16
12.18
12.17
1313.1
613
1414.1
661
14.2
14.3
14.4
14.5
14.6
1515.1
747
15.2
15.3
G.1
G.2
Truth-values for Conditional Operators
197
The return Statement
228
Granularities for Enabling and Disabling Assertions at Runtime
269
Enabling and Disabling Assertions in All System Classes at Runtime 272
Overriding vs. Overloading
293
Types and Values
317
Overview of Type Declarations
354
Selected Input Streams
477
Selected Output Streams
477
480
The DataInput and DataOutput Interfaces
Selected Readers
488
Selected Writers
490
Print Methods of the PrintWriter Class
491
Correspondence Between Selected Byte and Character Streams
500
Selected Language Codes
532
Selected Country Codes
532
Selected Predefined Locales for Languages
533
Selected Predefined Locales for Countries
533
Selected Field Numbers to Indicate Information in a Calendar
537
Selected Constants that Represent Values in a Calendar
538
Formatting Styles for Date and Time
542
Selected Characters
555
Selected Character Classes
556
Selected Predefined Character Classes
557
Boundary Matchers
557
Selected Logical Operators
558
Quantifier Classification
561
Implications of the Limit Value in the split() Method
564
Formatting Conversions
596
Flags
597
Selected Format Exceptions
601
Selected Time/Date Composition Conversions
601
Thread States
636
Summary of Subtyping Relationships for Generic Types
675
Get and Set Operations Using Parameterized References
682
Summary of Get and Set Operations using Parameterized References 684
Examples of Type Erasure
714
Examples of Reifiable Types
723
Examples of Non-Reifiable Types
723
Core Interfaces in the Collections Framework
779
Summary of Collection and Map Implementations
782
Bulk Operations and Set Logic
796
Number Systems
1005
Representing Signed byte Values Using 2’s Complement
1010
List of Examples
1.1
Basic Elements
of a Class Declaration
Chapter
11
1.2 Static Members in Class Declaration
1.3 Defining a Subclass
1.4 An Application
2.1
Default
for Fields
Chapter
2 Values
19
2.2 Flagging Uninitialized Local Variables of Primitive Data Types
2.3 Flagging Uninitialized Local Reference Variables
3.1
A JavaBean
Chapter
3 39
3.2 Using the this Reference
3.3 Namespaces
3.4 Using Enums
3.5 Declaring Enum Constructors and Members
3.6 Declaring Constant-Specific Class Bodies
3.7 Using Arrays
3.8 Using Anonymous Arrays
3.9 Using Multidimensional Arrays
3.10 Passing Primitive Values
3.11 Passing Reference Values
3.12 Passing Arrays
3.13 Array Elements as Primitive Data Values
3.14 Array Elements as Reference Values
3.15 Calling a Varargs Method
3.16 Passing Program Arguments
4.1
Defining
Packages and Using Type Import
Chapter
4 103
4.2 Single Static Import
4.3 Avoiding the Interface Constant Antipattern
4.4 Importing Enum Constants
4.5 Shadowing by Importing
4.6 Conflict in Importing Static Method with the Same Signature
4.7 Importing Nested Static Types
4.8 Using Properties
4.9 Class Scope
4.10 Accessibility Modifiers for Classes and Interfaces
3
8
11
15
33
34
35
42
46
49
55
56
60
73
75
78
83
84
86
88
88
91
95
107
110
110
111
112
113
114
123
131
133
xxix
xxx
LIST OF EXAMPLES
4.11 Abstract Classes
4.12 Public Accessibility of Members
4.13 Accessing Static Members
4.14 Accessing Final Members
4.15 Synchronized Methods
5.1
Operand
Evaluation Order
Chapter
5 159
5.2 Numeric Promotion in Arithmetic Expressions
5.3 Short-Circuit Evaluation Involving Conditional Operators
6.1
Fall Through
Chapter
6 203 in a switch Statement
6.2 Using break in a switch Statement
6.3 Nested switch Statement
6.4 Enums in switch Statement
6.5 The break Statement
6.6 Labeled break Statement
6.7 The continue Statement
6.8 Labeled continue Statement
6.9 The return Statement
6.10 Method Execution
6.11 The try-catch Construct
6.12 Exception Propagation
6.13 The try-catch-finally Construct
6.14 The try-finally Construct
6.15 The finally Block and the return Statement
6.16 Throwing Exceptions
6.17 The throws Clause
6.18 Using Assertions
7.1
Extending
Classes: Inheritance and Accessibility
Chapter
7 283
7.2 Overriding, Overloading, and Hiding
7.3 Using the super Keyword
7.4 Constructor Overloading
7.5 The this() Constructor Call
7.6 The super() Constructor Call
7.7 Interfaces
7.8 Variables in Interfaces
7.9 Assigning and Passing Reference Values
7.10 Choosing the Most Specific Method (Simple Case)
7.11 Overloaded Method Resolution
7.12 The instanceof and Cast Operators
7.13 Using the instanceof Operator
7.14 Polymorphism and Dynamic Method Lookup
7.15 Implementing Data Structures by Inheritance and Aggregation
8.1
Overview
of Type Declarations
Chapter
8 351
8.2 Static Member Types
8.3 Importing Static Member Types
8.4 Accessing Members in Enclosing Context (Static Member Classes)
8.5 Defining and Instantiating Non-static Member Classes
136
139
147
149
151
175
181
198
208
210
211
212
224
225
226
227
228
236
247
250
253
254
255
256
258
267
285
290
296
302
304
305
311
315
320
325
326
329
330
341
342
353
355
357
358
360
LIST OF EXAMPLES
Special Form of this and new Constructs in Non-static
Member Classes
8.7 Inheritance Hierarchy and Enclosing Context
8.8 Extending Inner Classes
8.9 Access in Enclosing Context (Local Classes)
8.10 Instantiating Local Classes
8.11 Objects of Local Classes as Caches
8.12 Defining Anonymous Classes
8.13 Accessing Declarations in Enclosing Context (Anonymous Classes)
9.1
Garbage
Collection Eligibility
Chapter
9 389
9.2 Using Finalizers
9.3 Invoking Garbage Collection
9.4 Initializer Expression Order and Method Calls
9.5 Exceptions in Initializer Expressions
9.6 Static Initializers and Forward References
9.7 Static Initializer Blocks and Exceptions
9.8 Instance Initializers and Forward References
9.9 Instance Initializer Block in Anonymous Class
9.10 Exception Handling in Instance Initializer Blocks
9.11 Object State Construction
9.12 Initialization under Object State Construction
10.1
Methods
the Object class
Chapter
10 in
423
10.2 String Representation of Integers
10.3 String Construction and Equality
10.4 Reading Characters from a String
11.1
Listing11
Files
Chapter
467Under a Directory
11.2 Copy a File
11.3 Reading and Writing Binary Values
11.4 Demonstrating Readers and Writers, and Character Encoding
11.5 Changing Passwords
11.6 Object Serialization
11.7 Non-Serializable Objects
11.8 Customized Serialization
11.9
Serialization and Inheritance
12.1
Understanding
Chapter
12 531 Locales
12.2 Using the Date class
12.3 Using the Calendar Class
12.4 Formatting Date/Time
12.5 Using the DateFormat class
12.6 Using the NumberFormat class
12.7 Splitting
12.8 String Pattern Matching
12.9 Match and Replace
12.10 Tokenizing Mode
12.11 Parsing Primitive Values and Strings
12.12 Using Delimiters and Patterns with a Scanner
xxxi
8.6
363
365
367
371
374
376
378
381
394
397
400
408
409
411
412
414
414
415
417
419
426
435
441
444
474
478
482
498
503
513
515
518
520
534
536
540
543
544
548
565
568
570
573
576
580
xxxii
LIST OF EXAMPLES
12.13 Multi-Line Mode
12.14 Using the format() Method
13.1
Implementing
Chapter
13 613 the Runnable Interface
13.2 Extending the Thread Class
13.3 Mutual Exclusion
13.4 Thread States
13.5 Waiting and Notifying
13.6 Joining of Threads
13.7 Thread Termination
13.8 Deadlock
14.1
A Legacy
Class
Chapter
14 661
14.2 A Generic Class for Nodes
14.3 A Generic Interface and its Implementation
14.4 Extending Generic Types
14.5 Unchecked Warnings
14.6 Illustrating Get and Set Operations Using Parameterized References
14.7 Implementing a Simplified Generic Stack
14.8 Declaring and Calling Generic Methods
14.9 Flexible Comparisons
14.10 Using Recursive Bounds
14.11 Using the @Override Annotation
14.12 Subsignatures
14.13 Overriding from Generic Supertype
14.14 Missing Supertype Parameterization
14.15 Genericity Cannot Be Added to Inherited Methods
14.16 Type Parameter in throws Clause
14.17 Generic Nested Classes
15.1
A Test15
Case
for Version Numbers
Chapter
747
15.2 Not Overriding the equals() and the hashCode() Methods
15.3 Testing the equals() and the hashCode() Methods
15.4 Implementing the equals() Method
15.5 Implications of Overriding the equals() Method
15.6 Implementing the hashCode() Method
15.7 Implications of Overriding the hashCode() Method
15.8 Implementing the compareTo() Method of the Comparable Interface
15.9 Implications of Implementing the compareTo() Method
15.10 Natural Ordering and Total Ordering
15.11 Using a Comparator for Version Numbers
15.12 Using an Iterator
15.13 Using a for(:) Loop to Iterate Over a Collection
15.14 Converting Collections to Arrays
15.15 Traversing Over Sets
15.16 Using Sets
15.17 Using Navigable Sets
15.18 Using Lists
15.19 Using Priority Queues
582
603
618
621
628
637
644
648
651
652
662
664
667
669
671
681
695
697
710
712
719
720
720
721
722
731
732
749
752
752
756
759
762
765
767
769
773
774
786
789
790
797
799
803
808
811
LIST OF EXAMPLES
15.20
15.21
15.22
xxxiii
Using Deques as a Stack and as a FIFO Queue
Using Maps
Using Navigable Maps
815
825
831
This page intentionally left blank
Foreword
Consider the following observations:
• Software continues to become ever more pervasive, ever more ubiquitous in
our lives.
• Incompetence seems to be the only thing we can count on in today’s world
and, especially, in the domain of software.
• The Java programming language has become a lingua franca for programmers
all over the world.
One can draw varied conclusions from these comments. One of them is that it is of
great importance that programmers working with the Java programming language should be as competent as possible.
The Java certification program is an important effort aimed at precisely this goal.
Practitioners looking to obtain such certification need good quality training materials, which brings us to this book.
Programming is still more of an art than a science, and will continue to be so for
the foreseeable future. Mastering the intricacies of a large and complex programming language is a challenging task that requires time and effort, and above all
experience.
Real programming requires more than just mastery of a programming language. It
requires mastery of a computing platform, with a rich set of libraries. These libraries are designed to simplify the task of building realistic applications, and they do.
Again, the practitioner is faced with a daunting task.
To address the clear need for professional training material, a plethora of books
have been written purporting to tutor programmers in the programming language
and platform skills they require.
The choice is as mind boggling as the material within the books themselves.
Should one try Java for Frontally Lobotomized Simians or Postmodern Java Dialectics?
The readership for these books is largely self selecting. I trust that if you, the reader,
xxxv
xxxvi
FOREWORD
have gotten this far, you are looking for something that is intelligent, yet practical.
This book is one of the finest efforts in this crowded arena. It brings a necessary
level of academic rigor to an area much in need of it, while retaining an essentially
pragmatic flavor.
The material in this book is probably all you need to pass the Java certification
exam. It certainly isn’t all you need to be a good software engineer. You must continue learning about new technologies. The hardest part of this is dealing with
things that are completely different from what you are familiar with. Yet this is
what distinguishes the top flight engineer from the mediocre one. Keep an open
mind; it pays.
Gilad Bracha
Computational Theologist
Sun Java Software
http://java.sun.com/people/gbracha/
Preface
Writing the Third Edition
The exam for the Sun Certified Programmer for Java Platform, Standard Edition 6,
has changed considerably since the second edition of this book was published. The
most noticeable change in the current version of the Sun Certified Java Programmer (SCJP) 1.6 exam is the inclusion of the features of Java 5, and the shifting of
emphasis towards analyzing code scenarios, rather than individual language constructs. In our opinion, the new exam demands an even greater understanding and
actual experience of the language, rather than mere recitation of facts. Proficiency
in the language is the key to success.
Since the emphasis of the SCJP 1.6 exam is on the core features of Java, the third
edition provides even greater in-depth coverage of the relevant topics. The book
covers not just the exam objectives, but also supplementary topics that aid in mastering the exam topics.
The third edition is still a one-source guide for the SCJP 1.6 exam: it provides a mixture of theory and practice for the exam. Use the book to learn Java, pass the SCJP
1.6 exam, and afterwards, use it as a handy language guide. The book also has an
appendix devoted to the SCJP 1.6 Upgrade exam.
We have taken into consideration the feedback we have received from readers. The
many hours spent in handling the deluge of e-mail have not been in vain. Every
single e-mail is appreciated and is hereby acknowledged.
Preparing the third edition dispelled our illusions about newer editions being, to
put it colloquially, a piece of cake. Every sentence from the second edition has been
weighed carefully, and not many paragraphs have escaped rewriting. UML (Unified Modeling Language) is also extensively employed in this edition. Numerous
new review questions have been added. In covering the new topics and expanding
the existing ones, new examples, figures, and tables were also specifically created
for the third edition.
xxxvii
xxxviii
PREFACE
About This Book
This book provides extensive coverage of the Java programming language and its
core Application Programming Interfaces (APIs), with particular emphasis on its
syntax and usage. The book is primarily intended for professionals who want to
prepare for the SCJP 1.6 exam, but it is readily accessible to any programmer who
wants to master the language. For both purposes, it provides in-depth coverage of
essential features of the language and its core APIs.
There is a great and increasing demand for certified Java programmers. Sun
Microsystems has defined the SCJP 1.6 exam as one that professionals can take to
validate their skills. The certification provides the IT industry with a standard to
use for hiring such professionals, and allows the professionals to turn their Java
skills into credentials that are important for career advancement.
The book provides extensive coverage of all the objectives defined for the exam by
Sun. But the exam objectives are selective and do not include many of the essential
features of Java. This book covers many additional topics that every Java programmer should master in order to be proficient. In this regard, the book is a comprehensive primer for learning the Java programming language. After mastering the
language by working through this book, the reader can confidently sit for the
exam.
This book is not a complete reference for Java, as it does not attempt to list every
member of every class from the Java Development Kit (JDK) API documentation.
The purpose is not to document the JDK APIs. This book does not teach
programming techniques. The emphasis is on the Java programming language
features, their syntax and correct usage through code examples.
The book assumes little background in programming. We believe the exam is
accessible to any programmer who works through the book. A Java programmer
can easily skip over material that is well understood and concentrate on parts that
need reinforcing, whereas a programmer new to Java will find the concepts
explained from basic principles.
Each topic is explained and discussed thoroughly with examples, and backed by
review questions and exercises to reinforce the concepts. The book is not biased
toward any particular platform, but provides platform-specific details where
necessary.
Using the Book
The reader can choose a linear or a non-linear route through the book, depending
on her programming background. Non-Java programmers wishing to migrate to
Java can read Chapter 1, which provides a short introduction to object-oriented
programming concepts, and the procedure for compiling and running Java appli-
PREFACE
xxxix
cations. For those preparing for the SCJP 1.6 exam, the book has a separate appendix providing all the pertinent information on taking the exam.
The table of contents; listings of tables, examples, and figures; and a comprehensive index facilitate locating topics discussed in the book.
In particular, we draw attention to the following features:
Exam Objectives
0.1 Exam objectives are stated clearly at the start of every chapter.
0.2 The number in front of the objective identfies the objective as defined by
Sun.
0.3 The objectives are organized into major sections, detailing the curriculum
for the exam.
0.4 The exam objectives are reproduced in Appendix B where, for each section
of the syllabus, references are included to point the reader to relevant topics
for the exam.
Supplementary Objectives
• Supplementary objectives cover topics that are not on the exam, but which
we believe are important for mastering the topics that are on the exam.
• Any supplementary objectives are listed as bullets at the beginning of a
chapter.
Review Questions
Review questions are provided after every major topic, in order to test and reinforce the material. These review questions reflect the kinds of questions that can be
asked on the actual exam. Annotated answers to the review questions are provided
in a separate appendix.
Example 0.1
Example Source Code
We encourage experimenting with the code examples in order to reinforce the
material from the book. These can be downloaded from the book Web site (see
p. xli).
Java code is written in a mono-spaced font. Lines of code in the examples or in code
snippets are referenced in the text by a number, which is specified by using a
single-line comment in the code. For example, in the following code snippet, the
call to the method doSomethingInteresting() hopefully does something interesting
at (1).
xl
PREFACE
// ...
doSomethingInteresting();
// ...
// (1)
Names of classes and interfaces start with an uppercase letter. Names of packages,
variables, and methods start with a lowercase letter. Constants are all in uppercase
letters. Interface names begin with the prefix 'I'. Coding conventions are followed, except when we have had to deviate in the interest of space or clarity.
Chapter Summary
Each chapter concludes with a summary of the topics, pointing out the major concepts discussed in the chapter.
Programming Exercises
Programming exercises at the end of each chapter provide the opportunity to put
concepts into practice. Solutions to the programming exercises are provided in a
separate appendix.
Mock Exam
A complete mock exam is provided in a separate appendix, which the reader can
try when she is ready.
Java SE API Documentation
A vertical gray bar is used to highlight methods and fields found in the classes
of the core Java APIs.
Any explanation following the API information is also similarly highlighted.
In order to obtain optimal benefit from using this book in preparing for the SCJP
1.6 exam, we strongly recommend installing the latest version (1.6 or newer) of the
JDK and its accompanying API documentation. The book focuses solely on Java,
and does not acknowledge previous versions.
Java Platform Upgrade Exam
For those who have taken the Sun Certified Programmer for Java Platform 1.5
Exam, and would like to prepare for the Sun Certified Programmer for Java Platform 1.6 Upgrade Exam, we have provided an appendix with details of the
upgrade exam. The appendix contains the upgrade exam objectives, and for each
section of the syllabus, references are included to point the reader to topics essential for the upgrade exam.
PREFACE
xli
Book Web Site
This book is backed by a Web site providing auxiliary material:
http://www.ii.uib.no/~khalid/pgjc3e/
The contents of the Web site include the following:
• source code for all the examples and programming exercises in the book
• mock exam engine
• errata
• links to miscellaneous Java resources (certification, discussion groups, tools, etc.)
Information about the Java Standard Edition and its documentation can be found
at the following Web site:
http://java.sun.com/javase/
The current authoritative technical reference for the Java programming language,
The Java Language Specification, Third Edition (also published by Addison-Wesley),
can be found at this Web site:
http://java.sun.com/docs/books/jls/
Request for Feedback
Considerable effort has been made to ensure the accuracy of the contents of this
book. Several Java professionals have proofread the manuscript. All code
examples (including code fragments) have been compiled and tested on various
platforms. In the final analysis, any errors remaining are the sole responsibility of
the authors.
Any questions, comments, suggestions, and corrections are welcome. Let us know
whether the book was helpful or detrimental for your purposes. Any feedback is
valuable. The authors can be reached by the following e-mail alias:
pgjc3e@ii.uib.no
About the Authors
Khalid A. Mughal
Khalid A. Mughal is an Associate Professor at the Department of Informatics at
the University of Bergen, Norway. Professor Mughal is responsible for designing
and implementing various courses, which use Java, at the Department of Informatics. Over the years, he has taught Programming Languages (Java, C/C++,
Pascal), Software Engineering (Object-Oriented System Development), Data-
xlii
PREFACE
bases (Data Modeling and Database Management Systems), and Compiler Techniques. He has also given numerous courses and seminars at various levels in
object-oriented programming and system development, using Java and Javarelated technology, both at the University and for the IT industry. He is the principal author of the book, responsible for writing the material covering the Java
topics.
Professor Mughal is also the principal author of an introductory Norwegian textbook on programming in Java (Java som første programmeringsspråk/Java as First Programming Language, Third Edition, Cappelen Akademisk Forlag, ISBN-10: 82-0224554-0, 2006), which he co-authored with Torill Hamre and Rolf W. Rasmussen.
Together they have also published another textbook for a 2-semester course in programming (Java Actually: A Comprehensive Primer in Programming, Cengage Learning, ISBN-10: 1844809331, 2008).
His current work involves applying Object Technology in the development of content management systems for publication on the Web, and security issues related
to web applications. For the past seven years he has been responsible for developing and running web-based programming courses in Java, which are offered to offcampus students.
He is also a member of the Association for Computing Machinery (ACM).
Rolf W. Rasmussen
Rolf W. Rasmussen is the System Development Manager at vizrt, a company that
develops solutions for the TV broadcast industry, including real-time 3D graphic
renderers, and content and control systems.
Rasmussen works mainly on control and automation systems, video processing,
typography, and real-time visualization. He has worked on clean room implementations of the Java class libraries in the past, and is a contributor to the Free Software Foundation.
Over the years, Rasmussen has worked both academically and professionally with
numerous programming languages, including Java. He is primarily responsible
for developing the review questions and answers, the programming exercises and
their solutions, the mock exam, and all the practical aspects related to taking the
SCJP exam presented in this book.
As mentioned above, he is also a co-author of two introductory textbooks on programming in Java.
Acknowledgments (First Edition)
A small application for drawing simple shapes is used in the book to illustrate
various aspects of GUI building. The idea for this application, as far as we know,
PREFACE
xliii
first appeared in Appendix D of Data Structures and Problem Solving Using Java
(M.A. Weiss, Addison-Wesley, 1998).
At Addison-Wesley-Longman (AWL), we would like to thank Emma Mitchell for
the support and the guidance she provided us right from the start of this project,
Martin Klopstock at AWL for accommodating the non-standard procedure
involved in getting the book to the printing press, Clive Birks at CRB Associates for
providing the professional look to the contents of this book, and finally, Sally
Mortimore at AWL for seeing us over the finishing line. The efforts of other professionals behind the scenes at AWL are also acknowledged.
Many reviewers have been involved during the course of writing this book. First
of all, we would like to thank the five anonymous reviewers commissioned by
AWL to review the initial draft. Their input was useful in the subsequent writing
of this book.
Several people have provided us with feedback on different parts of the material
at various stages: Jon Christian Lønningdal, Tord Kålsrud, Kjetil Iversen, Roy
Oma, and Arne Løkketangen. Their help is hereby sincerely acknowledged.
We are also very grateful to Laurence Vanhelsuwé, Kris Laporte, Anita Jacob, and
Torill Hamre for taking on the daunting task of reviewing the final draft, and
providing us with extensive feedback at such short notice. We would like to thank
Marit Mughal for reading the manuscript with the trained eye of a veteran English
schoolteacher.
We now understand why family members are invariably mentioned in a preface.
Without our families’ love, support, and understanding this book would have
remained a virtual commodity. Khalid would like to thank Marit, Nina, and Laila
for their love, and for being his pillars of support, during the writing of this book.
Thanks also to the folks in Birmingham for cheering us on. Rolf would like to thank
Liv, Rolf V., Knut, and Elisabeth for enduring the strange working hours producing
this book has entailed. A special thanks to Marit for providing us with scrumptious
dinners for consumption at the midnight hour.
Acknowledgments (Second Edition)
Feedback from many readers helped us to improve the first edition. We would like
to thank the following readers for their input in this effort:
Michael F. Adolf, Tony Alicea, Kåre Auglænd, Jorge L. Barroso, Andre Beland, Darren Bruning, Paul Campbell, Roger Chang, Joanna Chappel, Laurian M Chirica,
Arkadi Choufrine, Barry Colston, John Cotter, Frédéric Demers, Arthur De Souza,
djc, William Ekiel, Darryl Failla, John Finlay, Christopher R. Gardner, Marco Garcia, Peter Gieser, George, Paul Graf, Shyamsundar Gururaj, Ray Ho, Leonardo
Holanda, Zhu Hongjun, Kara Van Horn, Peter Horst, Nain Hwu, Kent Johnson,
Samir Kanparia, Oleksiy Karpenko, Jeffrey Kenyon, Young Jin Kim, Kenneth
xliv
PREFACE
Kisser, Billy Kutulas, Yi-Ming Lai, Robert M. Languedoc, Steve Lasley, Winser Lo,
Naga Madipalli, Craig Main, Avinash Mandsaurwale, Thomas Mathai, S. Mehra,
Yuan Meng, Simon Miller, William Moore, Anders Morch, George A. Murakami,
Sandy Nemecek, Chun Pan, Abigail García Patiño, Anil Philip, Alfred Raouf, Peter
Rorden, Christian Seifert, Gurpreet Singh, Christopher Stanwood, Swaminathan
Subramanian, Siva Sundaram, Manju Swamy, John Sweeney, Harmon Taylor,
Andrew Tolopko, Ravi Verma, Per J. Walstrøm, Chun Wang, James Ward, Winky,
Chun Wang, Jimmy Yang, Jennie Yip, Yanqu Zhou, and Yingting Zhou.
At the UK office of Addison-Wesley/Pearson Education, we would like to thank
our former editor Simon Plumtree for his unceasing support and patience while
we slogged on with the second edition. We would also like to acknowledge the
help and support of the following professionals, past and present, at the London
office: Alison Birtwell, Sally Carter, Karen Sellwood and Katherin Ekstrom. A special thanks to Karen Mosman (who has since moved on to another job) for her
encouragement and advice.
During the last lap of getting the book to the printing press, we were in the capable
hands of Ann Sellers at the US office of Addison-Wesley/Pearson Education. We
would like to acknowledge her efforts and that of other professionals—in particular, Greg Doench, Jacquelyn Doucette, Amy Fleischer, Michael Mullen, and Dianne
Russell—who helped to get this book through the door and on to the bookshelf.
Thanks also to Mike Hendrickson for always lending an ear when we met at the
OOPSLA conferences, and pointing us in the right direction with our book plans.
We would like to thank the folks at Whizlabs Software for their collaboration in
producing the contents for the CD accompanying this book. Those guys certainly know the business of developing exam simulators for certification in Java
technology.
We were fortunate in having two Java gurus—Laurence Vanhelsuwé and Marcus
Green—to do the technical review of the second edition. As he did for the first edition, Laurence came through and provided us with invaluable feedback, from the
minutiae of writing technical books to many technical issues relating to the Java
programming language. Marcus put the manuscript through his severe certification scrutiny regarding the specifics of the SCJP exam. We are sorry to have upset
their plans for Easter holidays, and hasten to thank them most profusely for taking
on the task.
We cannot thank enough our own in-house, private copy-editor: Marit Seljeflot
Mughal. She diligently and relentlessly read numerous drafts of the manuscript,
usually at very short notice. Marit claims that if she understood what we had written, then a computer-literate person should have no problem whatsoever. This
claim remains to be substantiated. If any commas are not used correctly, then it is
entirely our fault, in spite of being repeatedly shown how to use them.
We are also indebted to many Java-enabled individuals for providing us valuable
feedback on parts of the manuscript for the second edition. This includes Pradeep
Chopra, Seema R., and Gaurav Kohli at Whizlabs Software. Unfortunately for us,
PREFACE
xlv
they only had time to read part of the manuscript. Thanks also to Torill Hamre at
the Nansen Environmental and Remote Sensing Center, Bergen, for her useful
comments and suggestions. We also thank the following Master students at the
Department of Informatics, University of Bergen, for providing useful feedback:
Mikal Carlsen, Yngve Espelid, Yngve A. Aas, Sigmund Nysæter, Torkel Holm, and
Eskil Saatvedt.
Family support saw us through this writing project as well. Our families have put
up with our odd and long working hours, endured our preoccupation and our
absence at the dining table. Khalid would like to acknowledge the love and support of his wife, Marit, and daughters, Nina and Laila, while working on this book.
Rolf would like to thank Liv, Rolf V., Knut, and Elisabeth for their love, patience
and support.
Acknowledgments (Third Edition)
Many readers have sent us e-mails testifying that the Programmer’s Guide contributed toward their success on the exam. That is the best advertisement we can hope
for. The feedback we have received since the publication of the second edition has
had an impact on improving the third edition. In particular, we would like to thank
the following diligent readers for their contributions:
Bret ABMac, Einar Andresen, Brian Bradshaw, Nicola Cammillini, Juan Carlos
Castro, Sweta Doshi, David Featherstone, Danish Halim, Niels Harremoës, John
Holcroft, Leong Jern-Kuan, Rajesh Kesarwani, Ken Kisser, Shampa Kumar, Tony
LaPaso, Kaydell Leavitt, Luba Leyzerenok, Adam Lorentzon, Chuck Meier, Philip
Mitchell, Sigmund Nysæter, Pat Owens, Sanket Reddy, Raul Saavedra, Oliver Schoettler, Wayne Schroeter, Mark Sullivan, Myoung Son, Bob Souther, Anthony Tang,
Frederik Uyttersprot.
Erik Ernst was kind enough to review the chapter on Java generics, for which we
are very grateful. The generics chapter was also reviewed by Erik Andreas Brandstadmoen and Kristian Berg. Our sincere thanks to all of you. The pages of feedback we received helped to clarify many subtleties, and made us realize that some
dark corners of Java generics are best avoided by mere mortals.
Selected chapters for the third edition were also vetted by the following Java developers in the Bergen area: Olve Hansen, David J.M. Karlsen and Lars Søraas. Many
thanks for taking time out from your busy schedule to provide us with your feedback. Our thanks also to Helge W. Johnsen and Amund Trovåg for feedback on
review questions regarding new features in Java 1.5.
Our award for Reviewer Par Excellence goes to Jennie Yip. The meticulous notes
she provided for the ten chapters of the second edition have had a profound effect
on shaping the third edition. Any chance that the feat can be repeated with the
third edition? Please name your price.
xlvi
PREFACE
This time around we were again fortunate enough to have Marcus Green as our
technical reviewer. We have heeded his feedback that has kept us, we hope, on the
straight and narrow as far as the exam is concerned, and curbed our enthusiasm
for including every Java topic that we fancied. Our sincere thanks for the review
you provided us.
At Pearson, we would like to thank Greg Doench and Michelle Housley for managing the publication of this edition. We are also grateful to the people behind the
scenes at Pearson who helped get the book to the printing press.
Khalid would like to thank the Computer Science Department at Cornell University, where he spent a significant part of his sabbatical (Fall 2007/Spring 2008)
working on the third edition. A better place for such an endeavour would be hard
to come by.
We cannot thank enough Marit Seljeflot Mughal who has been our personal quality
controller, acting as an amalgamated draft reader, copy editor, and proofreader.
What she sanctioned we could confidently allow to be seen by the light of day, saving us many embarrassing mistakes, both technical and non-technical. We don’t
know if it is for us or for the love of Java that you scrutinize the endless drafts that
we lay in your path.
Any mistakes or errors remaining are an oversight on our part. Rest assured that
every possible effort has been made to get the facts straight.
Without family support this edition would still be wishful thinking. Khalid would
like to thank Marit, Laila, Nina and Kenneth for their love, support and understanding—particularly, while working on this book.
—Khalid A. Mughal
Rolf W. Rasmussen
September 2008
Ithaca, New York, USA
Bergen, Norway
Basics of Java Programming
1
Supplementary Objectives
• Introduce the basic terminology and concepts in object-oriented
programming: classes, objects, references, fields, methods, members,
inheritance, aggregation.
• Identify the essential elements of a Java program.
• Learn how to compile and run a Java program.
1
2
CHAPTER 1: BASICS OF JAVA PROGRAMMING
1.1 Introduction
Before embarking on the road to Java programmer certification, it is important to
understand the basic terminology and concepts in object-oriented programming
(OOP). In this chapter, the emphasis is on providing an introduction rather than
exhaustive coverage. In-depth coverage of the concepts follows in subsequent
chapters of the book.
Java supports the writing of many different kinds of executables: applications,
applets, and servlets. The basic elements of a Java application are introduced in
this chapter. The old adage that practice makes perfect is certainly true when learning a programming language. To encourage programming on the computer, the
mechanics of compiling and running a Java application are outlined.
1.2 Classes
One of the fundamental ways in which we handle complexity is in abstractions. An
abstraction denotes the essential properties and behaviors of an object that
differentiate it from other objects. The essence of OOP is modelling abstractions,
using classes and objects. The hard part in this endeavor is finding the right
abstraction.
A class denotes a category of objects, and acts as a blueprint for creating such
objects. A class models an abstraction by defining the properties and behaviors for
the objects representing the abstraction. An object exhibits the properties and
behaviors defined by its class. The properties of an object of a class are also called
attributes, and are defined by fields in Java. A field in a class is a variable which can
store a value that represents a particular property of an object. The behaviors of an
object of a class are also known as operations, and are defined using methods in Java.
Fields and methods in a class declaration are collectively called members.
An important distinction is made between the contract and the implementation that
a class provides for its objects. The contract defines what services, and the implementation defines how these services are provided by the class. Clients (i.e., other
objects) only need to know the contract of an object, and not its implementation, in
order to avail themselves of the object’s services.
As an example, we will implement different versions of a class that models the
abstraction of a stack that can push and pop characters. The stack will use an array
of characters to store the characters, and a field to indicate the top element in the
stack. Using Unified Modeling Language (UML) notation, a class called CharStack
is graphically depicted in Figure 1.1, which models the abstraction. Both fields and
method names are shown in Figure 1.1a.
3
1.2: CLASSES
Figure 1.1
UML Notation for Classes
Class Name
Fields
CharStack
stackArray
CharStack
topOfStack
Methods
push()
pop()
peek()
isEmpty()
isFull()
(b) Abbreviated Form
(a) Expanded Form
Declaring Members: Fields and Methods
Example 1.1 shows the declaration of the class CharStack depicted in Figure 1.1. Its
intention is to illustrate the salient features of a class declaration in Java, and not
the effective implementation of stacks.
A class declaration consists of a series of member declarations. In the case of the
class CharStack, it has two fields declared at (1):
• stackArray, which is an array to hold the elements of the stack (in this case,
characters)
• topOfStack, which denotes the top element of the stack (i.e., the index of the last
character stored in the array)
The class CharStack has five methods, declared at (3), that implement the essential
operations on a stack:
• push() pushes a character on to the stack
• pop() removes and returns the top element of the stack
• peek() returns the top element of the stack for inspection
• isEmpty() determines whether the stack is empty
• isFull() determines whether the stack is full
The class declaration also has a method-like declaration with the same name as the
class, (2). Such declarations are called constructors. As we shall see, a constructor is
executed when an object is created from the class. However, the implementation
details in the example are not important for the present discussion.
Example 1.1
Basic Elements of a Class Declaration
//Source Filename: CharStack.java
public class CharStack {
// Class name
// Class Declarations:
4
CHAPTER 1: BASICS OF JAVA PROGRAMMING
// Fields:
private char[] stackArray;
private int
topOfStack;
(1)
// The array implementing the stack.
// The top of the stack.
// Constructor:
public CharStack(int capacity) {
stackArray = new char[capacity];
topOfStack = -1;
}
// Methods:
public void push(char element)
public char pop()
public char peek()
public boolean isEmpty()
public boolean isFull()
{
{
{
{
{
(2)
(3)
stackArray[++topOfStack] = element; }
return stackArray[topOfStack--]; }
return stackArray[topOfStack]; }
return topOfStack < 0; }
return topOfStack == stackArray.length - 1; }
}
1.3 Objects
Class Instantiation, Reference Values, and References
The process of creating objects from a class is called instantiation. An object is an
instance of a class. The object is constructed using the class as a blueprint and is
a concrete instance of the abstraction that the class represents. An object must be
created before it can be used in a program.
A reference value is returned when an object is created. A reference value denotes a
particular object. An object reference (or simply reference) is a variable that can store
a reference value. A reference thus provides a handle to an object, as it can indirectly denote an object whose reference value it holds. In Java, an object can only
be manipulated via its reference value, or equivalently by a reference that holds its
reference value.
The process of creating objects usually involves the following steps:
1.
Declaration of a variable to store the reference value of an object.
This involves declaring a reference variable of the appropriate class to store the
reference value of the object.
// Declaration of two reference variables that will refer to
// two distinct objects, namely two stacks of characters, respectively.
CharStack stack1, stack2;
2.
Creating an object.
This involves using the new operator in conjunction with a call to a constructor,
to create an instance of the class.
// Create two distinct stacks of chars.
5
1.3: OBJECTS
stack1 = new CharStack(10); // Stack length: 10 chars
stack2 = new CharStack(5); // Stack length: 5 chars
The new operator creates an instance of the CharStack class and returns the reference value of this instance. The reference value can be assigned to a reference
variable of the appropriate class. The reference variable can then be used to
manipulate the object whose reference value is stored in the reference variable.
Each object has its own copy of the fields declared in the class declaration. The
two stacks, referenced by stack1 and stack2, will have their own stackArray and
topOfStack fields.
The purpose of the constructor call on the right side of the new operator is
to initialize the newly created object. In this particular case, for each new
CharStack instance created using the new operator, the constructor creates an
array of characters. The length of this array is given by the value of the argument to the constructor. The constructor also initializes the topOfStack field.
The declaration of a reference and the instantiation of the class can also be combined, as in the following declaration statement:
CharStack stack1 = new CharStack(10),
stack2 = new CharStack(5);
Figure 1.2 shows the UML notation for objects. The graphical representation of an
object is very similar to that of a class. Figure 1.2 shows the canonical notation,
where the name of the reference variable denoting the object is prefixed to the class
name with a colon (':'). If the name of the reference variable is omitted, as in Figure 1.2b, this denotes an anonymous object. Since objects in Java do not have
names, but are denoted by references, a more elaborate notation is shown in Figure
1.2c, where objects representing references of the CharStack class explicitly refer to
CharStack objects. In most cases, the more compact notation will suffice.
Figure 1.2
UML Notation for Objects
stack1:CharStack
stack2:CharStack
(a) Standard Notation for Objects
:CharStack
(b) Anonymous Object
stack1:Ref(CharStack)
:CharStack
stack2:Ref(CharStack)
:CharStack
(c) Explicit References for Java Objects
6
CHAPTER 1: BASICS OF JAVA PROGRAMMING
Object Aliases
An object can be referred by several references, meaning that they store the reference value of the same object. Such references are called aliases. The object can be
manipulated via any one of its aliases, as each one refers to the same object.
// Create two distinct stacks of chars.
CharStack stackA = new CharStack(12); // Stack length: 12 chars
CharStack stackB = new CharStack(6); // Stack length: 6 chars
stackB = stackA;
// (1) aliases after assignment
// The stack previously referenced by stackB can now be garbage collected.
Two stacks are created in the code above. Before the assignment at (1), the situation
is as depicted in Figure 1.3a. After the assignment at (1), the reference variables
stackA and stackB will denote the same stack, as depicted in Figure 1.3b. The reference value in stackA is assigned to stackB. The reference variables stackA and stackB
are aliases after the assignment, as they refer to the same object. What happens to
the stack object that was denoted by the reference variable stackB before the assignment? When objects are no longer in use, their memory is, if necessary, reclaimed
and reallocated for other objects. This is called automatic garbage collection. Garbage
collection in Java is taken care of by the runtime system.
Figure 1.3
Aliases
stackA:Ref(CharStack)
:CharStack
stackB:Ref(CharStack)
:CharStack
(a) Before
stackA:Ref(CharStack)
:CharStack
stackB:Ref(CharStack)
:CharStack
(b) After Assignment
1.4 Instance Members
Each object created will have its own copies of the fields defined in its class. The
fields of an object are called instance variables. The values of the instance variables
in an object comprise its state. Two distinct objects can have the same state, if their
instance variables have the same values. The methods of an object define its behavior. These methods are called instance methods. It is important to note that these
methods pertain to each object of the class. This should not be confused with the
7
1.5: STATIC MEMBERS
implementation of the methods, which is shared by all instances of the class.
Instance variables and instance methods, which belong to objects, are collectively
called instance members, to distinguish them from static members, which belong to
the class only. Static members are discussed in Section 1.5.
Invoking Methods
Objects communicate by message passing. This means that an object can be made
to exhibit a particular behavior by sending the appropriate message to the object.
In Java, this is done by calling a method on the object using the binary infix dot
('.') operator. A method call spells out the complete message: the object that is the
receiver of the message, the method to be invoked, and the arguments to the
method, if any. The method invoked on the receiver can also send information back
to the sender, via a single return value. The method called must be one that is
defined for the object, otherwise the compiler reports an error.
CharStack stack = new CharStack(5);
// Create a stack
stack.push('J');
// (1) Character 'J' pushed
char c = stack.pop();
// (2) One character popped and returned: 'J'
stack.printStackElements(); // (3) Compile-time error: No such method in CharStack
The sample code above invokes methods on the object denoted by the reference
variable stack. The method call at (1) pushes one character on the stack, and the
method call at (2) pops one character off the stack. Both push() and pop() methods
are defined in the class CharStack. The push() method does not return any value, but
the pop() method returns the character popped. Trying to invoke a method named
printStackElements on the stack results in a compile-time error, as no such method
is defined in the class CharStack.
The dot ('.') notation can also be used with a reference to access the fields of an
object. The use of the dot notation is governed by the accessibility of the member.
The fields in the class CharStack have private accessibility, indicating that they are
not accessible from outside the class:
stack.topOfStack++;
// Compile-time error: topOfStack is a private field.
1.5 Static Members
In some cases, certain members should only belong to the class, and not be part of
any object created from the class. An example of such a situation is when a class
wants to keep track of how many objects of the class have been created. Defining
a counter as an instance variable in the class declaration for tracking the number of
objects created does not solve the problem. Each object created will have its own
counter field. Which counter should then be updated? The solution is to declare the
counter field as being static. Such a field is called a static variable. It belongs to the
class, and not to any object of the class. A static variable is initialized when the class
is loaded at runtime. Similarly, a class can have static methods that belong to the
8
CHAPTER 1: BASICS OF JAVA PROGRAMMING
class, and not to any specific objects of the class. Static variables and static methods
are collectively known as static members, and are declared with the keyword static.
Figure 1.4 shows the class diagram for the class CharStack. It has been augmented
by two static members that are shown underlined. The augmented definition of the
CharStack class is given in Example 1.2. The field counter is a static variable declared
at (1). It will be allocated and initialized to the default value 0 when the class is
loaded. Each time an object of the CharStack class is created, the constructor at (2)
is executed. The constructor explicitly increments the counter in the class. The
method getInstanceCount() at (3) is a static method belonging to the class. It returns
the counter value when called.
Figure 1.4
Class Diagram Showing Static Members of a Class
CharStack
stackArray
topOfStack
counter
push()
pop()
peek()
...
getInstanceCount()
Example 1.2
Static Members in Class Declaration
//Filename CharStack.java
public class CharStack {
// Instance variables:
private char[] stackArray;
private int
topOfStack;
// The array implementing the stack.
// The top of the stack.
// Static variable
private static int counter;
// (1)
// Constructor now increments the counter for each object created.
public CharStack(int capacity) {
// (2)
stackArray = new char[capacity];
topOfStack = -1;
counter++;
}
// Instance methods:
public void push(char element)
public char pop()
public char peek()
public boolean isEmpty()
public boolean isFull()
{
{
{
{
{
stackArray[++topOfStack] = element; }
return stackArray[topOfStack--]; }
return stackArray[topOfStack]; }
return topOfStack < 0; }
return topOfStack == stackArray.length - 1; }
9
1.5: STATIC MEMBERS
// Static method
public static int getInstanceCount() { return counter; }
(3)
}
Figure 1.5 shows the classification of the members in the class CharStack using the
terminology we have introduced so far. Table 1.1 at the end of this section, provides
a summary of the terminology used in defining members of a class.
Clients can access static members in the class by using the class name. The following code invokes the getInstanceCount() method in the class CharStack:
int count = CharStack.getInstanceCount(); // Class name to invoke static method
Figure 1.5
Members of a Class
Class Name CharStack
Instance members belong to objects
Attributes
Static members belong to the class
Instance variables
Static variables
stackArray
topOfStack
counter
Fields
Members
Behaviour
Instance methods
Static methods
push()
pop()
peek()
isEmpty()
isFull()
getInstanceCount()
Objects
Methods
Class
Static members can also be accessed via object references, but this is considered
bad style:
CharStack stack1;
int count1 = stack1.getInstanceCount();
// Reference invokes static method
Static members in a class can be accessed both by the class name and via object references, but instance members can only be accessed by object references.
10
CHAPTER 1: BASICS OF JAVA PROGRAMMING
Table 1.1 Terminology for Class Members
Instance Members
These are instance variables and instance methods of an
object. They can only be accessed or invoked through an
object reference.
Instance Variable
A field that is allocated when the class is instantiated, i.e.,
when an object of the class is created. Also called non-static
field.
Instance Method
A method that belongs to an instance of the class. Objects of
the same class share its implementation.
Static Members
These are static variables and static methods of a class. They
can be accessed or invoked either by using the class name or
through an object reference.
Static Variable
A field that is allocated when the class is loaded. It belongs
to the class and not to any specific object of the class. Also
called static field or class variable.
Static Method
A method which belongs to the class and not to any object of
the class. Also called class method.
1.6 Inheritance
There are two fundamental mechanisms for building new classes from existing
ones: inheritance and aggregation. It makes sense to inherit from an existing class
Vehicle to define a class Car, since a car is a vehicle. The class Vehicle has several
parts; therefore, it makes sense to define a composite object of the class Vehicle that
has constituent objects of such classes as Motor, Axle, and GearBox, which make up a
vehicle.
Inheritance is illustrated by an example that implements a stack of characters that
can print its elements on the terminal. This new stack has all the properties and
behaviors of the CharStack class, but it also has the additional capability of printing
its elements. Given that this printable stack is a stack of characters, it can be
derived from the CharStack class. This relationship is shown in Figure 1.6. The class
PrintableCharStack is called the subclass, and the class CharStack is called the superclass. The CharStack class is a generalization for all stacks of characters, whereas the
Figure 1.6
Class Diagram Depicting Inheritance Relationship
Superclass
CharStack
Generalization
Subclass
PrintableCharStack
Specialization
11
1.6: INHERITANCE
class PrintableCharStack is a specialization of stacks of characters that can also print
their elements.
In Java, deriving a new class from an existing class requires the use of the extends
clause in the subclass declaration. A subclass can extend only one superclass. The
subclass can inherit members of the superclass. The following code fragment
implements the PrintableCharStack class:
class PrintableCharStack extends CharStack {
// Instance method
public void printStackElements() {
// ... implementation of the method...
}
// (1)
// (2)
// The constructor calls the constructor of the superclass explicitly.
public PrintableCharStack(int capacity) { super(capacity); }
// (3)
}
The PrintableCharStack class extends the CharStack class at (1). Implementing the
printStackElements() method in the PrintableCharStack class requires access to the
field stackArray from the superclass CharStack. However, this field is private and
therefore not accessible in the subclass. The subclass can access these fields if the
accessibility of the fields is changed to protected in the CharStack class. Example 1.3
uses a version of the class CharStack, which has been modified accordingly. Implementation of the printStackElements() method is shown at (2). The constructor of
the PrintableCharStack class at (3) calls the constructor of the superclass CharStack
in order to initialize the stack properly.
Example 1.3
Defining a Subclass
// Source Filename: CharStack.java
public class CharStack {
// Instance variables
protected char[] stackArray; // The array that implements the stack.
protected int
topOfStack; // The top of the stack.
// The rest of the definition is the same as in Example 1.2.
}
//Filename: PrintableCharStack.java
public class PrintableCharStack extends CharStack {
// (1)
// Instance method
public void printStackElements() {
// (2)
for (int i = 0; i <= topOfStack; i++)
System.out.print(stackArray[i]); // print each char on terminal
System.out.println();
}
// Constructor calls the constructor of the superclass explicitly.
PrintableCharStack(int capacity) { super(capacity); }
// (3)
}
12
CHAPTER 1: BASICS OF JAVA PROGRAMMING
Objects of the PrintableCharStack class will respond just like the objects of the CharStack class, but they will also have the additional functionality defined in the
subclass:
PrintableCharStack pcStack = new PrintableCharStack(3);
pcStack.push('H');
pcStack.push('i');
pcStack.push('!');
pcStack.printStackElements();
// Prints "Hi!" on the terminal
1.7 Aggregation
When building new classes from existing classes using aggregation, a composite
object is built from the constituent objects that are its parts.
Java supports aggregation of objects by reference, since objects cannot contain
other objects explicitly. The fields can only contain values of primitive data types
or reference values to other objects. Each object of the CharStack class has a field to
store the reference value of an array object that holds the characters. Each stack
object also has a field of primitive data type int to store the index value that
denotes the top of stack. This is reflected in the definition of the CharStack class,
which contains an instance variable for each of these parts. In contrast to the
constituent objects whose reference values are stored in fields, the values of primitive data types are themselves stored in the fields of the composite object. The
aggregation relationship is depicted by the UML diagram in Figure 1.7, showing
that each object of the CharStack class will have one array object of type char associated with it.
Figure 1.7
Class Diagram Depicting Aggregation
CharStack
stackArray
topOfStack
push()
pop()
peek()
...
has
1
Array of char
13
1.8: TENETS OF JAVA
1.8 Tenets of Java
• Code in Java must be encapsulated in classes.
• There are two kinds of values in Java: there are objects that are instances of
classes or arrays, and there are atomic values of primitive data types.
• References denote objects and are used to manipulate objects.
• Objects in Java cannot contain other objects; they can only contain references to
other objects.
• During execution, reclamation of objects that are no longer in use is managed
by the runtime system.
Review Questions
1.1
Which statement about methods is true?
Select the one correct answer.
(a)
(b)
(c)
(d)
(e)
1.2
A method is an implementation of an abstraction.
A method is an attribute defining the property of a particular abstraction.
A method is a category of objects.
A method is an operation defining the behavior for a particular abstraction.
A method is a blueprint for making operations.
Which statement about objects is true?
Select the one correct answer.
(a)
(b)
(c)
(d)
(e)
1.3
An object is what classes are instantiated from.
An object is an instance of a class.
An object is a blueprint for creating concrete realization of abstractions.
An object is a reference.
An object is a variable.
Which is the first line of a constructor declaration in the following code?
public class Counter {
int current, step;
public Counter(int startValue, int
setCurrent(startValue);
setStep(stepValue);
}
public int getCurrent()
public void setCurrent(int value)
public void setStep(int stepValue)
}
// (1)
stepValue) {
// (2)
{ return current; }
{ current = value; }
{ step = stepValue; }
// (3)
// (4)
// (5)
14
CHAPTER 1: BASICS OF JAVA PROGRAMMING
Select the one correct answer.
(a)
(b)
(c)
(d)
(e)
1.4
(1)
(2)
(3)
(4)
(5)
Given that Thing is a class, how many objects and how many reference variables are
created by the following code?
Thing item, stuff;
item = new Thing();
Thing entity = new Thing();
Select the two correct answers.
(a)
(b)
(c)
(d)
(e)
(f)
1.5
One object is created.
Two objects are created.
Three objects are created.
One reference variable is created.
Two reference variables are created.
Three reference variables are created.
Which statement about instance members is true?
Select the one correct answer.
(a)
(b)
(c)
(d)
(e)
1.6
An instance member is also called a static member.
An instance member is always a field.
An instance member is never a method.
An instance member belongs to an instance, not to the class as a whole.
An instance member always represents an operation.
How do objects communicate in Java?
Select the one correct answer.
(a)
(b)
(c)
(d)
1.7
They communicate by modifying each other’s fields.
They communicate by modifying the static variables of each other’s classes.
They communicate by calling each other’s instance methods.
They communicate by calling static methods of each other’s classes.
Given the following code, which statements are true?
class A {
int value1;
}
class B extends A {
int value2;
}
1.10: SAMPLE JAVA APPLICATION
15
Select the two correct answers.
(a)
(b)
(c)
(d)
(e)
(f)
Class A extends class B.
Class B is the superclass of class A.
Class A inherits from class B.
Class B is a subclass of class A.
Objects of class A have a field named value2.
Objects of class B have a field named value1.
1.9 Java Programs
A Java source file can contain more than one class declaration. Each source file name
has the extension .java. The JDK enforces the rule that any class in the source file
that has public accessibility must be declared in its own file; meaning that such a
public class must be declared in a source file whose file name comprises the name
of this public class with .java as its extension. The above rule implies that a source
file can only contain at the most one public class. If the source file contains a public
class, the file naming rule must be obeyed.
Each class declaration in a source file is compiled into a separate class file, containing Java byte code. The name of this file comprises the name of the class with .class
as its extension. The JDK provides tools for compiling and running programs, as
explained in the next section. The classes in the Java standard library are already
compiled, and the JDK tools know where to find them.
1.10 Sample Java Application
An application is just a synonym for a program: source code that is compiled and
directly executed. In order to create an application in Java, the program must have
a class that defines a method named main, which is the starting point for the execution of any application.
Essential Elements of a Java Application
Example 1.4 is an example of an application in which a client uses the CharStack
class to reverse a string of characters.
Example 1.4
An Application
// Source Filename: CharStack.java
public class CharStack {
// Same as in Example 1.2.
}
16
CHAPTER 1: BASICS OF JAVA PROGRAMMING
//Filename: Client.java
public class Client {
public static void main(String[] args) {
// Create a stack.
CharStack stack = new CharStack(40);
// Create a string to push on the stack:
String str = "!no tis ot nuf era skcatS";
int length = str.length();
System.out.println("Original string: " + str);
// Push the string char by char onto the stack:
for (int i = 0; i < length; i++) {
stack.push(str.charAt(i));
}
System.out.print("Reversed string: ");
// Pop and print each char from the stack:
while (!stack.isEmpty()) { // Check if the stack is not empty.
System.out.print(stack.pop());
}
System.out.println();
}
}
Output from the program:
Original string: !no tis ot nuf era skcatS
Reversed string: Stacks are fun to sit on!
The public class Client defines a method with the name main. To start the application, the main() method in this public class is invoked by the Java interpreter, also
called the Java Virtual Machine (JVM). The method header of this main() method
should be declared as shown in the following method stub:
public static void main(String[] args)
{ /* Implementation */ }
// Method header
The main() method has public accessibility, i.e., it is accessible from any class. The
keyword static means the method belongs to the class. The keyword void means
the method does not return any value. The parameter list, (String[] args), is an
array of strings that can be used to pass information to the main() method when the
application is started.
Compiling and Running an Application
Java source files can be compiled using the Java compiler tool javac, which is part
of the JDK.
1.10: SAMPLE JAVA APPLICATION
17
The source file Client.java contains the declaration of the Client class. The source
file can be compiled by giving the following command at the command line. (The
character > is the command prompt.)
>javac Client.java
This creates the class file Client.class containing the Java byte code for the Client
class. The Client class uses the CharStack class, and if the file CharStack.class does
not already exist, the compiler will also compile the source file CharStack.java.
Compiled classes can be executed by the Java interpreter java, which is also part of
the JDK. Example 1.4 can be run by giving the following command in the command line:
>java Client
Note that only the name of the class is specified, resulting in the execution starting
in the main() method of the specified class. The application in Example 1.4 terminates when the execution of the main() method is completed.
Review Questions
1.8
Which command from the JDK should be used to compile the following source
code contained in a file named SmallProg.java?
public class SmallProg {
public static void main(String[] args) { System.out.println("Good luck!"); }
}
Select the one correct answer.
(a) java SmallProg
(b) javac SmallProg
(c) java SmallProg.java
(d) javac SmallProg.java
(e) java SmallProg main
1.9
Which command from the JDK should be used to execute the main() method of a
class named SmallProg?
Select the one correct answer.
(a) java SmallProg
(b) javac SmallProg
(c) java SmallProg.java
(d) java SmallProg.class
(e) java SmallProg.main()
18
CHAPTER 1: BASICS OF JAVA PROGRAMMING
Chapter Summary
The following information was included in this chapter:
• basic concepts in OOP, and how they are supported in Java
• essential elements of a Java application
• compiling and running Java applications
Programming Exercise
1.1
Modify the program from Example 1.4 to use the PrintableCharStack class,
rather than the CharStack class from Example 1.2. Utilize the printStackElements() method from the PrintableCharStack class. Is the new program behaviorwise any different from Example 1.4?
Language Fundamentals
2
Exam Objectives
1.3 Develop code that declares, initializes, and uses primitives, arrays, enums,
and objects as static, instance, and local variables. Also, use legal
identifiers for variable names.
❍
For arrays, see Section 3.6, p. 69.
❍
For enums, see Section 3.5, p. 54.
❍
For initializers, see Section 9.7, p. 406.
Supplementary Objectives
• Be able to identify the basic elements of the Java programming language:
keywords, identifiers, literals and primitive data types.
• Understand the scope of variables.
• Understand initializing variables with default values.
19
20
CHAPTER 2: LANGUAGE FUNDAMENTALS
2.1 Basic Language Elements
Like any other programming language, the Java programming language is defined
by grammar rules that specify how syntactically legal constructs can be formed using
the language elements, and by a semantic definition that specifies the meaning of
syntactically legal constructs.
Lexical Tokens
The low-level language elements are called lexical tokens (or just tokens) and are the
building blocks for more complex constructs. Identifiers, numbers, operators, and
special characters are all examples of tokens that can be used to build high-level
constructs like expressions, statements, methods, and classes.
Identifiers
A name in a program is called an identifier. Identifiers can be used to denote classes,
methods, variables, and labels.
In Java, an identifier is composed of a sequence of characters, where each character
can be either a letter or a digit. However, the first character in an identifier must be
a letter. Since Java programs are written in the Unicode character set (see p. 23), the
definitions of letter and digit are interpreted according to this character set. Note
that connecting punctuation (such as underscore _) and any currency symbol (such as
$, ¢, ¥, or £) are allowed as letters, but should be avoided in identifier names.
Identifiers in Java are case sensitive, for example, price and Price are two different
identifiers.
Examples of Legal Identifiers
number, Number, sum_$, bingo, $$_100, mål, grüß
Examples of Illegal Identifiers
48chevy, all@hands, grand-sum
The name 48chevy is not a legal identifier as it starts with a digit. The character @ is
not a legal character in an identifier. It is also not a legal operator, so that all@hands
cannot be interpreted as a legal expression with two operands. The character - is
also not a legal character in an identifier. However, it is a legal operator so grandsum could be interpreted as a legal expression with two operands.
Keywords
Keywords are reserved words that are predefined in the language and cannot be
used to denote other entities. All the keywords are in lowercase, and incorrect
usage results in compilation errors.
21
2.1: BASIC LANGUAGE ELEMENTS
Keywords currently defined in the language are listed in Table 2.1. In addition,
three identifiers are reserved as predefined literals in the language: the null reference, and the boolean literals true and false (see Table 2.2). Keywords currently
reserved, but not in use, are listed in Table 2.3. A reserved word cannot be used as
an identifier. The index contains references to relevant sections where currently
used keywords are explained.
Table 2.1
Table 2.2
Keywords in Java
abstract
default
if
private
this
assert
do
implements
protected
throw
boolean
double
import
public
throws
break
else
instanceof
return
transient
byte
enum
int
short
try
case
extends
interface
static
void
catch
final
long
strictfp
volatile
char
finally
native
super
while
class
float
new
switch
continue
for
package
synchronized
Reserved Literals in Java
null
Table 2.3
true
false
Reserved Keywords not Currently in Use
const
goto
Literals
A literal denotes a constant value, i.e., the value that a literal represents remains
unchanged in the program. Literals represent numerical (integer or floating-point),
character, boolean or string values. In addition, there is the literal null that represents the null reference.
Table 2.4
Examples of Literals
Integer
2000
0
-7
Floating-point
3.14
-3.14
.5
0.5
Character
'a'
'A'
'0'
':'
Boolean
true
false
String
"abba"
"3.14"
"for"
'-'
')'
"a piece of the action"
22
CHAPTER 2: LANGUAGE FUNDAMENTALS
Integer Literals
Integer data types comprise the following primitive data types: int, long, byte, and
short (see Section 2.2, p. 28).
The default data type of an integer literal is always int, but it can be specified as
long by appending the suffix L (or l) to the integer value. Without the suffix, the
long literals 2000L and 0l will be interpreted as int literals. There is no direct way to
specify a short or a byte literal.
In addition to the decimal number system, integer literals can also be specified in
octal (base 8) and hexadecimal (base 16) number systems. Octal and hexadecimal
numbers are specified with a 0 and 0x (or 0X) prefix respectively. Examples of decimal, octal and hexadecimal literals are shown in Table 2.5. Note that the leading 0
(zero) digit is not the uppercase letter O. The hexadecimal digits from a to f can also
be specified with the corresponding uppercase forms (A to F). Negative integers
(e.g. -90) can be specified by prefixing the minus sign (-) to the magnitude of the
integer regardless of number system (e.g., -0132 or -0X5A). Number systems and
number representation are discussed in Appendix G. Java does not support literals
in binary notation.
Table 2.5
Examples of Decimal, Octal, and Hexadecimal Literals
Decimal
Octal
Hexadecimal
8
010
0x8
10L
012L
0xaL
16
020
0x10
27
033
0x1B
90L
0132L
0x5aL
-90
-0132
-0x5A
2147483647 (i.e., 2 -1)
017777777777
0x7fffffff
-2147483648 (i.e., -231)
-020000000000
-0x80000000
1125899906842624L (i.e., 250)
040000000000000000L
0x4000000000000L
31
Floating-Point Literals
Floating-point data types come in two flavors: float or double.
The default data type of a floating-point literal is double, but it can be explicitly
designated by appending the suffix D (or d) to the value. A floating-point literal can
also be specified to be a float by appending the suffix F (or f).
Floating-point literals can also be specified in scientific notation, where E (or e)
stands for Exponent. For example, the double literal 194.9E-2 in scientific notation is
interpreted as 194.9 × 10-2 (i.e., 1.949).
23
2.1: BASIC LANGUAGE ELEMENTS
Examples of double Literals
0.0
0.49
49.0
4.9E+1
0.0d
.49
49.
4.9E+1D
0D
.49D
49D
4.9e1d
4900e-2
.49E2
Examples of float Literals
0.0F
0.49F
49.0F
4.9E+1F
0f
.49F
49.F
4900e-2f
49F
.49E2F
Note that the decimal point and the exponent are optional and that at least one
digit must be specified.
Boolean Literals
The primitive data type boolean represents the truth-values true or false that are
denoted by the reserved literals true or false, respectively.
Character Literals
A character literal is quoted in single-quotes ('). All character literals have the
primitive data type char.
A character literal is represented according to the 16-bit Unicode character set,
which subsumes the 8-bit ISO-Latin-1 and the 7-bit ASCII characters. In Table 2.6,
note that digits (0 to 9), upper-case letters (A to Z), and lower-case letters (a to z) have
contiguous Unicode values. A Unicode character can always be specified as a fourdigit hexadecimal number (i.e., 16 bits) with the prefix \u.
Table 2.6
Examples of Character Literals
Character Literal
Character Literal using
Unicode value
Character
' '
'\u0020'
Space
'0'
'\u0030'
0
'1'
'\u0031'
1
'9'
'\u0039'
9
'A'
'\u0041'
A
'B'
'\u0042'
B
'Z'
'\u005a'
Z
'a'
'\u0061'
a
'b'
'\u0062'
b
Continues
24
CHAPTER 2: LANGUAGE FUNDAMENTALS
Table 2.6
Examples of Character Literals (Continued)
Character Literal
Character Literal using
Unicode value
Character
'z'
'\u007a'
z
'Ñ'
'\u0084'
Ñ
'å'
'\u008c'
å
'ß'
'\u00a7'
ß
Escape Sequences
Certain escape sequences define special characters, as shown in Table 2.7. These
escape sequences can be single-quoted to define character literals. For example, the
character literals '\t' and '\u0009' are equivalent. However, the character literals
'\u000a' and '\u000d' should not be used to represent newline and carriage return
in the source code. These values are interpreted as line-terminator characters by
the compiler, and will cause compile time errors. You should use the escape
sequences '\n' and '\r', respectively, for correct interpretation of these characters
in the source code.
Table 2.7
Escape Sequences
Escape Sequence
Unicode Value
Character
\b
\u0008
Backspace (BS)
\t
\u0009
Horizontal tab (HT or TAB)
\n
\u000a
Linefeed (LF) a.k.a. Newline (NL)
\f
\u000c
Form feed (FF)
\r
\u000d
Carriage return (CR)
\'
\u0027
Apostrophe-quote, a.k.a. single quote
\"
\u0022
Quotation mark, a.k.a. double quote
\\
\u005c
Backslash
We can also use the escape sequence \ddd to specify a character literal as an octal
value, where each digit d can be any octal digit (0–7), as shown in Table 2.8. The
number of digits must be three or fewer, and the octal value cannot exceed \377,
i.e., only the first 256 characters can be specified with this notation.
25
2.1: BASIC LANGUAGE ELEMENTS
Table 2.8
Examples of Escape Sequence \ddd
Escape Sequence \ddd
Character Literal
'\141'
'a'
'\46'
'&'
'\60'
'0'
String Literals
A string literal is a sequence of characters which must be enclosed in double quotes
and must occur on a single line. All string literals are objects of the class String (see
Section 10.4, p. 439).
Escape sequences as well as Unicode values can appear in string literals:
"Here comes a tab.\t And here comes another one\u0009!"
"What's on the menu?"
"\"String literals are double-quoted.\""
"Left!\nRight!"
"Don't split
me up!"
(1)
(2)
(3)
(4)
(5)
In (1), the tab character is specified using the escape sequence and the Unicode
value, respectively. In (2), the single apostrophe need not be escaped in strings, but
it would be if specified as a character literal ('\''). In (3), the double quotes in the
string must be escaped. In (4), we use the escape sequence \n to insert a newline.
(5) generates a compile time error, as the string literal is split over several lines.
Printing the strings from (1) to (4) will give the following result:
Here comes a tab.
And here comes another one
What's on the menu?
"String literals are double-quoted."
Left!
Right!
!
One should also use the escape sequences \n and \r, respectively, for correct interpretation of the characters \u000a (newline) and \u000d (form feed) in string literals.
White Spaces
A white space is a sequence of spaces, tabs, form feeds, and line terminator characters in a Java source file. Line terminators can be newline, carriage return, or a carriage return-newline sequence.
A Java program is a free-format sequence of characters that is tokenized by the compiler, i.e., broken into a stream of tokens for further analysis. Separators and operators help to distinguish tokens, but sometimes white space has to be inserted
26
CHAPTER 2: LANGUAGE FUNDAMENTALS
explicitly as a separator. For example, the identifier classRoom will be interpreted as
a single token, unless white space is inserted to distinguish the keyword class from
the identifier Room.
White space aids not only in separating tokens, but also in formatting the program
so that it is easy to read. The compiler ignores the white spaces once the tokens are
identified.
Comments
A program can be documented by inserting comments at relevant places in the
source code. These comments are for documentation purposes only and are
ignored by the compiler.
Java provides three types of comments to document a program:
• A single-line comment: // ... to the end of the line
• A multiple-line comment: /* ... */
• A documentation (Javadoc) comment: /** ... */
Single-Line Comment
All characters after the comment-start sequence // through to the end of the line
constitute a single-line comment.
// This comment ends at the end of this line.
int age;
// From comment-start sequence to the end of the line is a comment.
Multiple-Line Comment
A multiple-line comment, as the name suggests, can span several lines. Such a comment starts with the sequence /* and ends with the sequence */.
/* A comment
on several
lines.
*/
The comment-start sequences (//, /*, /**) are not treated differently from other
characters when occurring within comments, and are thus ignored. This means
that trying to nest multiple-line comments will result in a compile time error:
/* Formula for alchemy.
gold = wizard.makeGold(stone);
/* But it only works on Sundays. */
*/
The second occurrence of the comment-start sequence /* is ignored. The last occurrence of the sequence */ in the code is now unmatched, resulting in a syntax error.
REVIEW QUESTIONS
27
Documentation Comment
A documentation comment is a special-purpose comment that is used by the javadoc
tool to generate HTML documentation for the program. Documentation comments
are usually placed in front of classes, interfaces, methods, and field definitions.
Special tags can be used inside a documentation comment to provide more specific
information. Such a comment starts with the sequence /** and ends with the
sequence */:
/**
* This class implements a gizmo.
* @author K.A.M.
* @version 3.0
*/
For details on the javadoc tool, see the tools documentation provided by the JDK.
Review Questions
2.1
Which of the following is not a legal identifier?
Select the one correct answer.
(a) a2z
(b) ödipus
(c) 52pickup
(d) _class
(e) ca$h
2.2
Which statement is true?
Select the one correct answer.
(a)
(b)
(c)
(d)
(e)
(f)
2.3
new and delete are keywords in the Java language.
try, catch, and thrown are keywords in the Java language.
static, unsigned, and long are keywords in the Java language.
exit, class, and while are keywords in the Java language.
return, goto, and default are keywords in the Java language.
for, while, and next are keywords in the Java language.
Which statement about the following comment is true?
/* // */
Select the one correct answer.
(a) The comment is not valid. The multiple-line comment (/* ... */) does not
end correctly, since the comment-end sequence */ is a part of the single-line
comment (// ...).
(b) It is a completely valid comment. The // part is ignored by the compiler.
(c) This combination of comments is illegal, and will result in a compile
time error.
28
CHAPTER 2: LANGUAGE FUNDAMENTALS
2.2 Primitive Data Types
Figure 2.1 gives an overview of the primitive data types in Java.
Primitive data types in Java can be divided into three main categories:
• integral types—represent signed integers (byte, short, int, long) and unsigned
character values (char)
• floating-point types (float, double)—represent fractional signed numbers
• boolean type (boolean)—represents logical values
Figure 2.1
Primitive Data Types in Java
Primitive data types
Boolean type
Numeric types
Integral types
Floating-point types
Character type
Integer types
char
byte short int long
boolean
float double
Primitive data values are not objects. Each primitive data type defines the range of
values in the data type, and operations on these values are defined by special
operators in the language (see Chapter 5).
Each primitive data type also has a corresponding wrapper class that can be used
to represent a primitive value as an object. Wrapper classes are discussed in Section
10.3, p. 428.
Integer Types
Table 2.9
Range of Integer Values
Data Type
Width
(bits)
Minimum value
MIN_VALUE
Maximum value
MAX_VALUE
byte
8
-27 (-128)
27-1 (+127)
short
16
-215 (-32768)
215-1 (+32767)
int
32
-231 (-2147483648)
231-1 (+2147483647)
long
64
-263 (-9223372036854775808L)
263-1 (+9223372036854775807L)
29
2.2: PRIMITIVE DATA TYPES
Integer data types are byte, short, int, and long (see Table 2.9). Their values are
signed integers represented by 2’s complement (see Section G.4, p. 1010).
The char Type
Table 2.10
Range of Character Values
Data
Type
Width (bits)
Minimum Unicode value
Maximum Unicode value
char
16
0x0 (\u0000)
0xffff (\uffff)
The data type char represents characters (see Table 2.10). Their values are unsigned
integers that denote all the 65536 (216) characters in the 16-bit Unicode character
set. This set includes letters, digits, and special characters.
The first 128 characters of the Unicode set are the same as the 128 characters of the
7-bit ASCII character set, and the first 256 characters of the Unicode set correspond
to the 256 characters of the 8-bit ISO Latin-1 character set.
The integer types and the char type are collectively called integral types.
The Floating-Point Types
Table 2.11
Range of Floating-Point Values
Data Type
Width
(bits)
Minimum Positive Value
MIN_VALUE
Maximum Positive Value
MAX_VALUE
float
32
1.401298464324817E-45f
3.402823476638528860e+38f
double
64
4.94065645841246544e-324
1.79769313486231570e+308
Floating-point numbers are represented by the float and double data types.
Floating-point numbers conform to the IEEE 754-1985 binary floating-point standard. Table 2.11 shows the range of values for positive floating-point numbers, but
these apply equally to negative floating-point numbers with the '-' sign as a prefix. Zero can be either 0.0 or -0.0.
Since the size for representation is a finite number of bits, certain floating-point
numbers can only be represented as approximations. For example, the value of the
expression (1.0/3.0) is represented as an approximation due to the finite number
of bits used.
30
CHAPTER 2: LANGUAGE FUNDAMENTALS
The boolean Type
Table 2.12
Boolean Values
Data Type
Width
True Value Literal
False Value Literal
boolean
not applicable
true
false
The data type boolean represents the two logical values denoted by the literals true
and false (see Table 2.12).
Boolean values are produced by all relational (see Section 5.10, p. 190), conditional
(see Section 5.13, p. 196) and boolean logical operators (see Section 5.12, p. 194), and
are primarily used to govern the flow of control during program execution.
Table 2.13 summarizes the pertinent facts about the primitive data types: their
width or size, which indicates the number of the bits required to store a primitive
value; their range of legal values, which is specified by the minimum and the maximum values permissible; and the name of the corresponding wrapper class (see
Section 10.3, p. 428).
Table 2.13
Summary of Primitive Data Types
Data Type
Width (bits)
Minimum Value, Maximum Value
Wrapper Class
boolean
not applicable
true, false
Boolean
byte
8
-27, 27-1
Byte
short
16
-2 , 2 -1
Short
char
16
0x0, 0xffff
Character
int
32
-231, 231-1
Integer
long
64
-2 , 2 -1
Long
float
32
±1.40129846432481707e-45f,
±3.402823476638528860e+38f
Float
double
64
±4.94065645841246544e-324,
±1.79769313486231570e+308
Double
15
63
15
63
31
2.3: VARIABLE DECLARATIONS
Review Questions
2.4
Which of the following do not denote a primitive data value in Java?
Select the two correct answers.
(a) "t"
(b) 'k'
(c) 50.5F
(d) "hello"
(e) false
2.5
Which of the following primitive data types are not integer types?
Select the three correct answers.
(a) boolean
(b) byte
(c) float
(d) short
(e) double
2.6
Which integral type in Java has the exact range from -2147483648 (-231) to
2147483647 (231-1), inclusive?
Select the one correct answer.
(a) byte
(b) short
(c) int
(d) long
(e) char
2.3 Variable Declarations
A variable stores a value of a particular type. A variable has a name, a type, and a
value associated with it. In Java, variables can only store values of primitive data
types and reference values of objects. Variables that store reference values of
objects are called reference variables (or object references or simply references).
Declaring and Initializing Variables
Variable declarations are used to specify the type and the name of variables. This
implicitly determines their memory allocation and the values that can be stored in
them. Examples of declaring variables that can store primitive values:
char a, b, c;
double area;
boolean flag;
// a, b and c are character variables.
// area is a floating-point variable.
// flag is a boolean variable.
32
CHAPTER 2: LANGUAGE FUNDAMENTALS
The first declaration above is equivalent to the following three declarations:
char a;
char b;
char c;
A declaration can also include an initialization expression to specify an appropriate initial value for the variable:
int i = 10,
j = 101;
long big = 2147483648L;
// i is an int variable with initial value 10.
// j is an int variable with initial value 101.
// big is a long variable with specified initial value.
Reference Variables
An reference variable can store the reference value of an object, and can be used to
manipulate the object denoted by the reference value.
A variable declaration that specifies a reference type (i.e., a class, an array, or an
interface name) declares a reference variable. Analogous to the declaration of variables of primitive data types, the simplest form of reference variable declaration
only specifies the name and the reference type. The declaration determines what
objects can be referenced by a reference variable. Before we can use a reference
variable to manipulate an object, it must be declared and initialized with the reference value of the object.
Pizza yummyPizza;
// Variable yummyPizza can reference objects of class Pizza.
Hamburger bigOne,
// Variable bigOne can reference objects of class Hamburger,
smallOne; // and so can variable smallOne.
It is important to note that the declarations above do not create any objects of class
Pizza or Hamburger. The above declarations only create variables that can store references of objects of the specified classes.
A declaration can also include an initializer expression to create an object whose
reference value can be assigned to the reference variable:
Pizza yummyPizza = new Pizza("Hot&Spicy"); // Declaration with initializer.
The reference variable yummyPizza can reference objects of class Pizza. The keyword
new, together with the constructor call Pizza("Hot&Spicy"), creates an object of the
class Pizza. The reference value of this object is assigned to the variable yummyPizza.
The newly created object of class Pizza can now be manipulated through the reference variable yummyPizza.
Initializers for initializing fields in objects, and static variables in classes and interfaces are discussed in Section 9.7, p. 406.
Reference variables for arrays are discussed in Section 3.6, p. 69.
33
2.4: INITIAL VALUES FOR VARIABLES
2.4 Initial Values for Variables
Default Values for Fields
Default values for fields of primitive data types and reference types are listed in
Table 2.14. The value assigned depends on the type of the field.
Table 2.14
Default Values
Data Type
Default Value
boolean
false
char
'\u0000'
Integer (byte, short, int, long)
0L for long, 0 for others
Floating-point (float, double)
0.0F or 0.0D
Reference types
null
If no initialization is provided for a static variable either in the declaration or in a
static initializer block (see Section 9.9, p. 410), it is initialized with the default value
of its type when the class is loaded.
Similarly, if no initialization is provided for an instance variable either in the declaration or in an instance initializer block (see Section 9.10, p. 413), it is initialized
with the default value of its type when the class is instantiated.
The fields of reference types are always initialized with the null reference value if
no initialization is provided.
Example 2.1 illustrates default initialization of fields. Note that static variables are
initialized when the class is loaded the first time, and instance variables are initialized accordingly in every object created from the class Light.
Example 2.1
Default Values for Fields
public class Light {
// Static variable
static int counter;
// Default value 0 when class is loaded.
// Instance variables:
int
noOfWatts = 100; // Explicitly set to 100.
boolean indicator;
// Implicitly set to default value false.
String location;
// Implicitly set to default value null.
public static void main(String[] args) {
Light bulb = new Light();
System.out.println("Static variable counter: "
+ Light.counter);
System.out.println("Instance variable noOfWatts: " + bulb.noOfWatts);
34
CHAPTER 2: LANGUAGE FUNDAMENTALS
System.out.println("Instance variable indicator: " + bulb.indicator);
System.out.println("Instance variable location: " + bulb.location);
return;
}
}
Output from the program:
Static variable counter: 0
Instance variable noOfWatts: 100
Instance variable indicator: false
Instance variable location: null
Initializing Local Variables of Primitive Data Types
Local variables are variables that are declared in methods, constructors, and blocks
(see Chapter 3, p. 39). Local variables are not initialized when they are created at
method invocation, that is, when the execution of a method is started. The same
applies in constructors and blocks. Local variables must be explicitly initialized
before being used. The compiler will report as errors any attempts to use uninitialized local variables.
Example 2.2
Flagging Uninitialized Local Variables of Primitive Data Types
public class TooSmartClass {
public static void main(String[] args) {
int weight = 10, thePrice;
if (weight < 10) thePrice = 1000;
if (weight > 50) thePrice = 5000;
if (weight >= 10) thePrice = weight*10;
System.out.println("The price is: " + thePrice);
// (1) Local variables
// (2) Always executed.
// (3)
}
}
In Example 2.2, the compiler complains that the local variable thePrice used in the
println statement at (3) may not be initialized. However, it can be seen that at runtime, the local variable thePrice will get the value 100 in the last if-statement at (2),
before it is used in the println statement. The compiler does not perform a rigorous
analysis of the program in this regard. It only compiles the body of a conditional
statement if it can deduce the condition to be true. The program will compile correctly if the variable is initialized in the declaration, or if an unconditional assignment is made to the variable.
Replacing the declaration of the local variables at (1) in Example 2.2 with the following declaration solves the problem:
int weight = 10, thePrice = 0;
// (1') Both local variables initialized.
2.4: INITIAL VALUES FOR VARIABLES
35
Initializing Local Reference Variables
Local reference variables are bound by the same initialization rules as local variables of primitive data types.
Example 2.3
Flagging Uninitialized Local Reference Variables
public class VerySmartClass {
public static void main(String[] args) {
String importantMessage;
// Local reference variable
System.out.println("The message length is: " + importantMessage.length());
}
}
In Example 2.3, the compiler complains that the local variable importantMessage
used in the println statement may not be initialized. If the variable importantMessage is set to the value null, the program will compile. However, a runtime error
(NullPointerException) will occur when the code is executed, since the variable
importantMessage will not denote any object. The golden rule is to ensure that a reference variable, whether local or not, is assigned a reference to an object before it
is used, that is, ensure that it does not have the value null.
The program compiles and runs if we replace the declaration with the following
declaration of the local variable, which creates a string literal and assigns its reference value to the local reference variable importantMessage:
String importantMessage = "Initialize before use!";
Arrays and their default values are discussed in Section 3.6, p. 69.
Lifetime of Variables
The lifetime of a variable, that is, the time a variable is accessible during execution,
is determined by the context in which it is declared. The lifetime of a variable is
also called scope, and is discussed in more detail in Section 4.6, p. 129. We distinguish between lifetime of variables in three contexts:
• Instance variables—members of a class, and created for each object of the class.
In other words, every object of the class will have its own copies of these variables, which are local to the object. The values of these variables at any given
time constitute the state of the object. Instance variables exist as long as the
object they belong to is in use at runtime.
• Static variables—also members of a class, but not created for any specific object
of the class and, therefore, belong only to the class (see Section 4.6, p. 129). They
are created when the class is loaded at runtime, and exist as long as the class is
available at runtime.
36
CHAPTER 2: LANGUAGE FUNDAMENTALS
• Local variables (also called method automatic variables)—declared in methods,
constructors, and blocks; and created for each execution of the method, constructor, or block. After the execution of the method, constructor, or block completes, local (non-final) variables are no longer accessible.
Review Questions
2.7
Which declarations are valid?
Select the three correct answers.
(a) char a = '\u0061';
(b) char 'a' = 'a';
(c) char \u0061 = 'a';
(d) ch\u0061r a = 'a';
(e) ch'a'r a = 'a';
2.8
Given the following code within a method, which statement is true?
int a, b;
b = 5;
Select the one correct answer.
(a)
(b)
(c)
(d)
(e)
2.9
Local variable a is not declared.
Local variable b is not declared.
Local variable a is declared but not initialized.
Local variable b is declared but not initialized.
Local variable b is initialized but not declared.
In which of these variable declarations will the variable remain uninitialized
unless it is explicitly initialized?
Select the one correct answer.
(a)
(b)
(c)
(d)
(e)
2.10
Declaration of an instance variable of type int.
Declaration of a static variable of type float.
Declaration of a local variable of type float.
Declaration of a static variable of type Object.
Declaration of an instance variable of type int[].
What will be the result of compiling and running the following program?
public class Init {
String title;
boolean published;
static int total;
static double maxPrice;
PROGRAMMING EXERCISE
37
public static void main(String[] args) {
Init initMe = new Init();
double price;
if (true)
price = 100.00;
System.out.println("|" + initMe.title + "|" + initMe.published + "|" +
Init.total + "|" + Init.maxPrice + "|" + price+ "|");
}
}
Select the one correct answer.
(a)
(b)
(c)
(d)
(e)
The program will fail to compile.
The program will compile, and print |null|false|0|0.0|0.0|, when run.
The program will compile, and print |null|true|0|0.0|100.0|, when run.
The program will compile, and print | |false|0|0.0|0.0|, when run.
The program will compile, and print |null|false|0|0.0|100.0|, when run.
Chapter Summary
The following information was included in this chapter:
• basic language elements: identifiers, keywords, literals, white space, and
comments
• primitive data types: integral, floating-point, and boolean
• notational representation of numbers in decimal, octal, and hexadecimal systems
• declaration and initialization of variables, including reference variables
• usage of default values for instance variables and static variables
• lifetime of instance variables, static variables, and local variables
Programming Exercise
2.1
The following program has several errors. Modify the program so that it will
compile and run without errors.
// Filename: Temperature.java
PUBLIC CLASS temperature {
PUBLIC void main(string args) {
double fahrenheit = 62.5;
*/ Convert /*
double celsius = f2c(fahrenheit);
System.out.println(fahrenheit + 'F' + " = " + Celsius + 'C');
}
double f2c(float fahr) {
RETURN (fahr - 32) * 5 / 9;
}
}
This page intentionally left blank
Declarations
3
Exam Objectives
1.3 Develop code that declares, initializes, and uses primitives, arrays, enums,
and objects as static, instance, and local variables. Also, use legal
identifiers for variable names.
❍
Enums and arrays are covered in this chapter.
❍
For primitive types, see Section 2.2, p. 28.
❍
For initialization of static, instance, and local variables, see Section 2.3, p. 31.
For initializers, see Section 9.7, p. 406.
1.4 Develop code that declares both static and non-static methods, and—if
appropriate—use method names that adhere to the JavaBeans naming
standards. Also develop code that declares and uses a variable-length
argument list.
1.5 Given a code example, determine if a method is correctly overriding or
overloading another method, and identify legal return values (including
covariant returns), for the method.
❍
❍
For overloaded method resolution, see Section 7.10, p. 324.
❍
For overriding methods, see Section 7.2, p. 288.
❍
For return values, see Section 6.4, p. 228.
For covariant return, see Section 7.2, p. 290.
1.6 Given a set of classes and superclasses, develop constructors for one or
more of the classes. Given a class declaration, determine if a default
constructor will be created and, if so, determine the behavior of that
constructor. Given a nested or non-nested class listing, write code to
instantiate the class.
❍
❍
For constructor chaining, see Section 7.5, p. 302, and Section 9.11, p. 416.
For instantiating nested classes, see Chapter 8.
7.2 Given an example of a class and a command-line, determine the expected
runtime behavior.
7.3 Determine the effect upon object references and primitive values when
they are passed into methods that perform assignments or other
modifying operations on the parameters.
❍
❍
For conversions in assignment and method invocation contexts, see Section 5.2,
p. 163.
39
40
CHAPTER 3: DECLARATIONS
3.1 Class Declarations
A class declaration introduces a new reference type. It has the following general
syntax:
class
// Class header
{ // Class body
}
In the class header, the name of the class is preceded by the keyword class. In
addition, the class header can specify the following information:
• accessibility modifier (see Section 4.7, p. 132)
• additional class modifiers (see Section 4.8, p. 135)
• a formal type parameter list, if the class is generic (see Section 14.2, p. 663)
• any class it extends (see Section 7.1, p. 284)
• any interfaces it implements (see Section 7.6, p. 309)
The class body can contain member declarations which comprise:
• field declarations (see Section 2.3, p. 31)
• method declarations (see Section 3.3, p. 44)
• nested class, enum, and interface declarations (see Section 8.1, p. 352)
Members declared static belong to the class and are called static members. Nonstatic members belong to the objects of the class and are called instance members. In
addition, the following can be declared in a class body:
• constructor declarations (see Section 3.4, p. 48)
• static and instance initializer blocks (see Section 9.7, p. 406)
The member declarations, constructor declarations, and initializer blocks can
appear in any order in the class body.
In order to understand what code can be legally declared in a class, we distinguish
between static context and non-static context. A static context is defined by static
methods, static field initializers, and static initializer blocks. A non-static context
is defined by instance methods, constructors, non-static field initializers, and
instance initializer blocks. By static code we mean expressions and statements in a
static context, and similarly by non-static code we mean expressions and statements
3.2: JAVABEANS STANDARD
41
in a non-static context. One crucial difference between the two contexts is that
static code can only refer to other static members.
3.2 JavaBeans Standard
The JavaBeans Standard allows reusable software components to be modelled in
Java so that these components can be assembled to create sophisticated applications. In particular, builder tools can take advantage of how these components are
specified, in order to build new applications based on these components. The JavaBeans specification specifies the rules for defining such components (called JavaBeans). The interested reader is encouraged to consult this documentation (see
http://java.sun.com/javase/technologies/desktop/javabeans/docs/spec.html) for
details since we only cover the basic fundamentals for creating JavaBeans .
Naming Patterns for Properties
The rules of the JavaBean specification stipulate naming patterns for declaring properties of JavaBeans. A naming pattern defines a standard naming convention. A
property of an object is normally defined as a field in the object, which is usually
not directly accessible by clients (see Example 3.1). A JavaBean should adhere to
the following naming patterns when specifying its properties:
• The properties are assumed to be private, and their names start with a lowercase letter. Example 3.1 shows that the JavaBean class Light has three properties.
• In order to retrieve and change values of its properties, a JavaBean provides
getter and setter methods for them. Example 3.1 shows a JavaBean with three
getter and three setter methods for its properties.
• For a property, the setter method starts with the prefix set. The rest of the
method name is assumed to be a property name, where the first letter of the
property name has been converted to uppercase. In Example 3.1, the value of
the property noOfWatts can be changed by the setter method setNoOfWatts().
Setter methods are public and void, having a parameter of the same type as that
of the property.
• For a property, the getter method starts with the prefix get. The rest of the
method name is assumed to be a property name, where the first letter of the
property name has been converted to uppercase. In Example 3.1, the value of
the property noOfWatts can be retrieved by the getter method getNoOfWatts().
For a boolean property, the getter method can start with the prefix get or is. In
Example 3.1, the value of the boolean property indicator can be retrieved by the
getter method isIndicator().
Getter methods are no-argument public methods that return a value of the
same type as the parameter of the corresponding setter method.
42
Example 3.1
CHAPTER 3: DECLARATIONS
A JavaBean
public class Light {
// Properties:
private int
noOfWatts;
private String location;
private boolean indicator;
// wattage
// placement
// on or off
// Setters
public void setNoOfWatts(int noOfWatts)
{ this.noOfWatts = noOfWatts; }
public void setLocation(String location)
{ this.location = location; }
public void setIndicator(boolean indicator) { this.indicator = indicator; }
// Getters
public int
getNoOfWatts() { return noOfWatts; }
public String getLocation() { return location; }
public boolean isIndicator() { return indicator; }
}
Naming Patterns for the Event Model
A listener is an object that is interested in being notified when a particular event
takes place. The origin of this event is usually an object called the source, which
notifies interested listeners when the event occurs. In this setup, a listener can be
added to or removed from the list of listeners notified by a source about the occurrence of a particular event. This setup is the basis of the event model which is
depicted in Figure 3.1.
The JavaBean specification stipulates naming patterns for the event model to facilitate its use by builder tools to assemble event-based applications. Figure 3.1 shows
where the naming patterns for handling events of type X are applied:
• An event class with the name XEvent, that extends the java.util.EventObject
class.
public class XEvent extends java.util.EventObject {
public XEvent(Object source) {
super(source);
}
}
• A listener interface with the name XListener, that specifies the specific method
to be called in a listener when an event of the type XEvent occurs. The listener
interface extends the java.util.EventListener interface.
public interface XListener extends java.util.EventListener {
public void methodAInXListener(XEvent ev);
}
A listener interested in XEvents must implement the XListener interface, and
must be registered with the source in order to be informed about XEvents.
43
3.2: JAVABEANS STANDARD
Figure 3.1 The Event Model
addXListener(listener)
event X
source
addXListener(XListener l)
removeXListener(XListener l)
methodAInXListener(
) : XEvent
«interface»
java.util.EventObject
listener
methodAInXListener(XEvent e)
«interface»
XListener
«interface»
java.util.EventListener
methodAInXListener(XEvent e)
A listener interested in XEvent events is registered with the source using the addXListener() method.
The listener must implement the XListener interface in order to recieve events of type XEvent.
The listener is informed about events of type XEvent via the methodAInXListener()
in the XListener interface.
public class ListenerObject implements XListener {
public void methodAInXListener(XEvent e) { /* ... */ }
}
• A source for XEvent, that implements the methods addXListener() and removeXListener(). These methods are used to add or remove a listener interested in
XEvents, respectively. The parameter of these methods is of the type XListener.
public class SourceObject {
public synchronized void addXListener(XListener listener) { /* ... */ }
public synchronized void removeXListener(XListener listener) { /* ... */ }
}
Note that there are no naming patterns defined for the names of the source and the
listener classes. Neither is there any standard convention for naming the methods
specified in the listener interface.
44
CHAPTER 3: DECLARATIONS
3.3 Method Declarations
The general syntax of a method declaration is
() // Method header
{ // Method body
}
In addition to the name of the method, the method header can specify the following information:
• scope or accessibility modifier (see Section 4.9, p. 138)
• additional method modifiers (see Section 4.10, p. 146)
• a formal type parameter list, if the declaration is for a generic method (see Section
14.8, p. 697)
• the type of the return value, or void if the method does not return any value (see
Section 6.4, p. 228)
• a formal parameter list (see below)
• checked exceptions thrown by the method are specified in a throws clause (see
Section 6.9, p. 257)
The formal parameter list is a comma-separated list of parameters for passing information to the method when the method is invoked by a method call (see Section 3.7,
p. 81). An empty parameter list must be specified by ( ). Each parameter is a simple
variable declaration consisting of its type and name:
The parameter names are local to the method (see Section 4.6, p. 131). The parameter modifier final is discussed in Section 3.7 on page 89.
The signature of a method comprises the method name and the formal parameter
list only.
The method body is a block containing the local declarations and the statements of the
method. Local variable declarations are discussed in Section 2.3 on page 31, and
nested local class declarations in Section 8.4 on page 371.
Like member variables, member methods can be characterized as:
• instance methods
• static methods, which are discussed in Section 4.10, p. 148.
3.3: METHOD DECLARATIONS
45
Statements
Statements in Java can be grouped into various categories. Variable declarations
with explicit initialization of the variables are called declaration statements (see Section 2.3, p. 31, and Section 3.6, p. 71). Other basic forms of statements are control
flow statements (see Section 6.1, p. 204) and expression statements.
An expression statement is an expression terminated by a semicolon. The expression
is evaluated for its side effect and its value discarded. Only certain types of expressions have meaning as statements. They include the following:
• assignments (see Section 5.5, p. 169)
• increment and decrement operators (see Section 5.8, p. 186)
• method calls (see Section 3.7, p. 81)
• object creation expressions with the new operator (see Section 5.15, p. 201)
A solitary semicolon denotes the empty statement that does nothing.
A block, {}, is a compound statement which can be used to group zero or more local
declarations and statements (see Section 4.6, p. 131). Blocks can be nested, since a
block is a statement that can contain other statements. A block can be used in any
context where a simple statement is permitted. The compound statement which is
embodied in a block, begins at the left brace, {, and ends with a matching right
brace, }. Such a block must not be confused with an array initialization block in
declaration statements (see Section 3.6, p. 71).
Labeled statements are discussed in Section 6.4 on page 223.
Instance Methods and the Object Reference this
Instance methods belong to every object of the class and can only be invoked on
objects. All members defined in the class, both static and non-static, are accessible
in the context of an instance method. The reason is that all instance methods are
passed an implicit reference to the current object, that is, the object on which the
method is being invoked. The current object can be referenced in the body of the
instance method by the keyword this. In the body of the method, the this reference
can be used like any other object reference to access members of the object. In fact,
the keyword this can be used in any non-static context. The this reference can be
used as a normal reference to reference the current object, but the reference cannot
be modified—it is a final reference (Section 4.10, p. 148).
The this reference to the current object is useful in situations where a local variable
hides, or shadows, a field with the same name. In Example 3.2, the two parameters
noOfWatts and indicator in the constructor of the Light class have the same names
as the fields in the class. The example also declares a local variable location, which
has the same name as one of the fields. The reference this can be used to distinguish the fields from the local variables. At (1), the this reference is used to identify
the field noOfWatts, which is assigned the value of the parameter noOfWatts. Without
46
CHAPTER 3: DECLARATIONS
the this reference at (2), the value of the parameter indicator is assigned back to
this parameter, and not to the field by the same name, resulting in a logical error.
Similarly at (3), without the this reference, it is the local variable location that is
assigned the value of the parameter site, and not the field by the same name.
Example 3.2
Using the this Reference
public class Light {
// Fields:
int
noOfWatts;
boolean indicator;
String location;
// wattage
// on or off
// placement
// Constructor
public Light(int noOfWatts, boolean indicator, String site) {
String location;
this.noOfWatts = noOfWatts;
indicator = indicator;
location = site;
this.superfluous();
superfluous();
//
//
//
//
//
(1) Assignment to field.
(2) Assignment to parameter.
(3) Assignment to local variable.
(4)
equivalent to call at (4)
}
public void superfluous() { System.out.println(this); }
// (5)
public static void main(String[] args) {
Light light = new Light(100, true, "loft");
System.out.println("No. of watts: " + light.noOfWatts);
System.out.println("Indicator: "
+ light.indicator);
System.out.println("Location: "
+ light.location);
}
}
Output from the program:
Light@df6ccd
Light@df6ccd
No. of watts: 100
Indicator: false
Location: null
If a member is not shadowed by a local declaration, the simple name member is considered a short-hand notation for this.member. In particular, the this reference can
be used explicitly to invoke other methods in the class. This is illustrated at (4) in
Example 3.2, where the method superfluous() is called.
If, for some reason, a method needs to pass the current object to another method,
it can do so using the this reference. This is illustrated at (5) in Example 3.2, where
the current object is passed to the println() method.
47
3.3: METHOD DECLARATIONS
Note that the this reference cannot be used in a static context, as static code is not
executed in the context of any object.
Method Overloading
Each method has a signature, which comprises the name of the method, and the
types and order of the parameters in the formal parameter list. Several method
implementations may have the same name, as long as the method signatures differ.
This is called method overloading. Since overloaded methods have the same name,
their parameter lists must be different.
Rather than inventing new method names, method overloading can be used
when the same logical operation requires multiple implementations. The Java
standard library makes heavy use of method overloading. For example, the class
java.lang.Math contains an overloaded method min(), which returns the minimum
of two numeric values.
public
public
public
public
static
static
static
static
double min(double a, double b)
float min(float a, float b)
int min(int a, int b)
long min(long a, long b)
In the following examples, five implementations of the method methodA are shown:
void
int
int
long
long
methodA(int a, double b) {
methodA(int a)
{
methodA()
{
methodA(double a, int b) {
methodA(int x, double y) {
/* ...
return
return
return
return
*/
a;
1;
b;
x;
}
}
}
}
}
//
//
//
//
//
(1)
(2)
(3)
(4)
(5) Not OK.
The corresponding signatures of the five methods are as follows:
methodA(int, double)
methodA(int)
methodA()
methodA(double, int)
methodA(int, double)
1'
2': Number of parameters.
3': Number of parameters.
4': Order of parameters.
5': Same as 1'.
The first four implementations of the method named methodA are overloaded correctly, each time with a different parameter list and, therefore, different signatures.
The declaration at (5) has the same signature methodA(int, double) as the declaration at (1) and is, therefore, not a valid overloading of this method.
void bake(Cake k) { /* ... */ }
void bake(Pizza p) { /* ... */ }
// (1)
// (2)
int
double
// (3)
// (4) Not OK. Same signature.
halfIt(int a) { return a/2; }
halfIt(int a) { return a/2.0; }
The method named bake is correctly overloaded at (1) and (2), with two different
signatures. In the implementation, changing just the return type (as shown at (3)
and (4) above), is not enough to overload a method, and will be flagged as a compile-time error. The parameter list in the declarations must be different.
48
CHAPTER 3: DECLARATIONS
Only methods declared in the same class and those that are inherited by the class
can be overloaded. Overloaded methods should be considered as individual methods that just happen to have the same name. Methods with the same name are
allowed, since methods are identified by their signature. At compile time, the right
implementation of an overloaded method is chosen based on the signature of the
method call. Details of method overloading resolution can be found in Section 7.10
on page 324. Method overloading should not be confused with method overriding
(see Section 7.2, p. 288).
3.4 Constructors
The main purpose of constructors is to set the initial state of an object, when the
object is created by using the new operator.
A constructor has the following general syntax:
()
// Constructor header
{ // Constructor body
}
Constructor declarations are very much like method declarations. However, the
following restrictions on constructors should be noted:
• Modifiers other than an accessibility modifier are not permitted in the constructor header. For accessibility modifiers for constructors, see Section 4.9 on
page 138.
• Constructors cannot return a value and, therefore, do not specify a return
type, not even void, in the constructor header. But their declaration can use
the return statement that does not return a value in the constructor body (Section 6.4, p. 228).
• The constructor name must be the same as the class name.
Class names and method names exist in different namespaces. Thus, there are no
name conflicts in Example 3.3, where a method declared at (2) has the same name
as the constructor declared at (1). However, using such naming schemes is strongly
discouraged.
49
3.4: CONSTRUCTORS
Example 3.3
Namespaces
public class Name {
Name() {
// (1)
System.out.println("Constructor");
}
void Name() {
// (2)
System.out.println("Method");
}
public static void main(String[] args) {
new Name().Name();
// (3) Constructor call followed by method call.
}
}
Output from the program:
Constructor
Method
The Default Constructor
A default constructor is a constructor without any parameters, i.e., it is a no-parameter constructor. It has the following signature:
()
If a class does not specify any constructors, then an implicit default constructor is
generated for the class by the compiler. The implicit default constructor is equivalent to the following implementation:
() { super(); }
// No parameters. Calls superclass constructor.
The only action taken by the implicit default constructor is to call the superclass
constructor. This ensures that the inherited state of the object is initialized properly
(see Section 7.5, p. 302). In addition, all instance variables in the object are set to the
default value of their type, barring those that are initialized by an initialization
expression in their declaration.
In the following code, the class Light does not specify any constructors.
class Light {
// Fields:
int
noOfWatts;
boolean indicator;
String location;
// No constructors
//...
}
// wattage
// on or off
// placement
50
CHAPTER 3: DECLARATIONS
class Greenhouse {
// ...
Light oneLight = new Light();
}
// (1) Call to implicit default constructor.
In the code above, the following implicit default constructor is called when a Light
object is created by the object creation expression at (1):
Light() { super(); }
Creating an object using the new operator with the implicit default constructor, as
at (1), will initialize the fields of the object to their default values (that is, the fields
noOfWatts, indicator, and location in a Light object will be initialized to 0, false, and
null, respectively).
A class can choose to provide an implementation of the default constructor. In the
following example, the class Light provides an explicit default constructor at (1).
Note that it has the same name as the class, and that it does not specify any parameters.
class Light {
// ...
// Explicit
Light() {
noOfWatts
indicator
location
}
//...
}
Default Constructor:
// (1)
= 50;
= true;
= "X";
class Greenhouse {
// ...
Light extraLight = new Light();
}
// (2) Call of explicit default constructor.
The explicit default constructor ensures that any object created with the object creation expression new Light(), as at (2), will have its fields noOfWatts, indicator and
location initialized to 50, true and "X", respectively.
If a class defines any explicit constructors, it can no longer rely on the implicit
default constructor to set the state of its objects. If such a class requires a default
constructor, its implementation must be provided. In the example below, the class
Light only provides a non-default constructor at (1). It is called at (2) when an
object of the class Light is created with the new operator. Any attempt to call the
default constructor will be flagged as a compile-time error, as shown at (3).
class Light {
// ...
// Only non-default Constructor:
Light(int noOfWatts, boolean indicator, String location) {
this.noOfWatts = noOfWatts;
this.indicator = indicator;
this.location = location;
}
// (1)
51
3.4: CONSTRUCTORS
//...
}
class Greenhouse {
// ...
Light moreLight = new Light(100, true, "Greenhouse");
//Light firstLight = new Light();
error.
}
// (2) OK.
// (3) Compile-time
Overloaded Constructors
Like methods, constructors can also be overloaded. Since the constructors in a class
all have the same name as the class, their signatures are differentiated by their
parameter lists. In the following example, the class Light now provides both an
explicit implementation of the default constructor at (1) and a non-default constructor at (2). The constructors are overloaded, as is evident by their signatures.
The non-default constructor is called when an object of the class Light is created at
(3), and the default constructor is likewise called at (4). Overloading of constructors allows appropriate initialization of objects on creation, depending on the constructor invoked (see also chaining of constructors in Section 7.5, p. 302.)
class Light {
// ...
// Explicit
Light() {
noOfWatts
indicator
location
}
Default Constructor:
// (1)
= 50;
= true;
= "X";
// Non-default Constructor:
Light(int noOfWatts, boolean indicator, String location) { // (2)
this.noOfWatts = noOfWatts;
this.indicator = indicator;
this.location = location;
}
//...
}
class Greenhouse {
// ...
Light moreLight = new Light(100, true, "Greenhouse");
Light firstLight = new Light();
}
// (3) OK.
// (4) OK.
52
CHAPTER 3: DECLARATIONS
Review Questions
3.1
Which one of these declarations is a valid method declaration?
Select the one correct answer.
(a) void method1
{ /*
(b) void method2()
{ /*
(c) void method3(void) { /*
(d) method4()
{ /*
(e) method5(void)
{ /*
3.2
...
...
...
...
...
*/
*/
*/
*/
*/
}
}
}
}
}
Which statements, when inserted at (1), will not result in compile-time errors?
public class ThisUsage {
int planets;
static int suns;
public void gaze() {
int i;
// (1) INSERT STATEMENT HERE
}
}
Select the three correct answers.
(a) i = this.planets;
(b) i = this.suns;
(c) this = new ThisUsage();
(d) this.i = 4;
(e) this.suns = planets;
3.3
Given the following pairs of method declarations, which statements are true?
void fly(int distance) {}
int fly(int time, int speed) { return time*speed; }
void fall(int time) {}
int fall(int distance) { return distance; }
void glide(int time) {}
void Glide(int time) {}
Select the two correct answers.
(a) The first pair of methods will compile, and overload the method name fly.
(b) The second pair of methods will compile, and overload the method name
fall.
(c) The third pair of methods will compile, and overload the method name glide.
(d) The second pair of methods will not compile.
(e) The third pair of methods will not compile.
53
3.4: CONSTRUCTORS
3.4
Given a class named Book, which one of these constructor declarations is valid for
the class Book?
Select the one correct answer.
(a) Book(Book b) {}
(b) Book Book() {}
(c) private final Book() {}
(d) void Book() {}
(e) public static void Book(String[] args) {}
(f) abstract Book() {}
3.5
Which statements are true?
Select the two correct answers.
(a)
(b)
(c)
(d)
(e)
3.6
A class must define a constructor.
A constructor can be declared private.
A constructor can return a value.
A constructor must initialize all fields when a class is instantiated.
A constructor can access the non-static members of a class.
What will be the result of compiling the following program?
public class MyClass {
long var;
public void MyClass(long param) { var = param; }
public static void main(String[] args) {
MyClass a, b;
a = new MyClass();
b = new MyClass(5);
}
// (1)
// (2)
// (3)
}
Select the one correct answer.
(a) A compilation error will occur at (1), since constructors cannot specify a
return value.
(b) A compilation error will occur at (2), since the class does not have a default
constructor.
(c) A compilation error will occur at (3), since the class does not have a constructor that takes one argument of type int.
(d) The program will compile without errors.
54
CHAPTER 3: DECLARATIONS
3.5 Enumerated Types
An enumerated type defines a finite set of symbolic names and their values. These symbolic names are usually called enum constants or named constants. One way to define
such constants is to declare them as final, static variables in a class (or interface)
declaration:
public class MachineState
public static final int
public static final int
public static final int
}
{
BUSY = 1;
IDLE = 0;
BLOCKED = -1;
Such constants are not typesafe, as any int value can be used where we need to use
a constant declared in the MachineState class. Such a constant must be qualified by
the class (or interface) name, unless the class is extended (or the interface is implemented). When such a constant is printed, only its value (for example, 0), and not
its name (for example, IDLE) is printed. A constant also needs recompiling if its
value is changed, as the values of such constants are compiled into the client code.
An enumerated type in Java is much more powerful than the approach outlined
above. It is certainly more convenient to use than implementing one from scratch
using the typesafe enum pattern (see Effective Java by Josh Bloch, ISBN-10:
0321356683).
Declaring Typesafe Enums
The canonical form of declaring an enum type is shown below.
enum MachineState { BUSY, IDLE, BLOCKED } // Canonical form
The keyword enum is used to declare an enum type. The basic notation requires the
type name and a comma-separated list of enum constants. In this case, the name of the
enum type is MachineState. It defines three enum constants. An enum constant can
be any legal Java identifier, but the convention is to use uppercase letters in the
name. Essentially, an enum declaration defines a reference type that has a finite
number of permissible values referenced by the enum constants, and the compiler
ensures they are used in a typesafe manner.
Using Typesafe Enums
Example 3.4 illustrates using enum constants. An enum type is essentially used as
any other reference type, and the restrictions are noted later in this section. Enum
constants are in fact final, static variables of the enum type, and they are implicitly initialized with objects of the enum type when the enum type is loaded at runtime. Since the enum constants are static members, they can be accessed using the
name of the enum type—analogous to accessing static members in a class.
55
3.5: ENUMERATED TYPES
Example 3.4 shows a machine client that uses a machine whose state is an enum
constant. From Example 3.4, we see that an enum constant can be passed as an
argument, as shown as (1), and we can declare references whose type is an enum
type, as shown as (3), but we cannot create new constants (that is, objects) of the
enum type MachineState. An attempt to do so at (5), results in a compile-time error.
The string representation of an enum constant is its name, as shown at (4). Note
that it is not possible to pass a type of value other than a MachineState enum constant in the call to the method setState() of the Machine class, as shown at (2).
Example 3.4
Using Enums
// Filename: MachineState.java
public enum MachineState { BUSY, IDLE, BLOCKED }
// Filename: Machine.java
public class Machine {
private MachineState state;
public void setState(MachineState state) { this.state = state; }
public MachineState getState() { return this.state; }
}
// Filename: MachineClient.java
public class MachineClient {
public static void main(String[] args) {
Machine machine = new Machine();
machine.setState(MachineState.IDLE);
// machine.setState(1);
// (1) Passed as a value.
// (2) Compile-time error!
MachineState state = machine.getState();
// (3) Declaring a reference.
System.out.println(
"The machine state is: " + state
// (4) Printing the enum name.
);
// MachineState newState = new MachineState();// (5) Compile-time error!
}
}
Output from the program:
The machine state is: IDLE
Declaring Enum Constructors and Members
An enum type declaration is a special kind of reference type declaration. It can
declare constructors and other members as in an ordinary class, but the enum constants must be declared before any other declarations (see the declaration of the
56
CHAPTER 3: DECLARATIONS
enum type Meal in Example 3.5). The list of enum constants must be terminated by
a semi-colon (;). Each enum constant name can be followed by an argument list
that is passed to the constructor of the enum type having the matching parameter
signature.
In Example 3.5, the enum type Meal contains a constructor declaration at (1) with
the following signature:
Meal(int, int)
Each enum constant is specified with an argument list with the signature (int,
int) that matches the constructor signature. In addition, the enum declaration
declares two fields for the meal time at (3), and two instance methods to retrieve
the meal time at (4).
When the enum type is loaded at runtime, the constructor is run for each enum
constant, passing the argument values specified for the enum constant. For the Meal
enum type, three objects are created that are initialized with the specified argument values, and are referenced by the three enum constants, respectively. Note
that each enum constant is a final, static reference that stores the reference value
of an object of the enum type, and methods of the enum type can be called on this
object by using the enum constant name. This is illustrated at (5) in Example 3.5 by
calling methods on the object referenced by the enum constant Meal.BREAKFAST.
An implicit standard constructor is created if no constructors are provided for the
enum type. As mentioned earlier, an enum type cannot be instantiated using the
new operator. The constructors cannot be called explicitly. The only accessibility
modifier allowed for a constructor is private.
Example 3.5
Declaring Enum Constructors and Members
// Filename: Meal.java
public enum Meal {
BREAKFAST(7,30), LUNCH(12,15), DINNER(19,45);
}
// (1)
// Non-default constructor
Meal(int hh, int mm) {
assert (hh >= 0 && hh <= 23): "Illegal hour.";
assert (mm >= 0 && mm <= 59): "Illegal mins.";
this.hh = hh;
this.mm = mm;
}
(2)
// Fields for the meal time:
private int hh;
private int mm;
(3)
// Instance methods:
public int getHour() { return this.hh; }
public int getMins() { return this.mm; }
(4)
57
3.5: ENUMERATED TYPES
// Filename: MealAdministrator.java
public class MealAdministrator {
public static void main(String[] args) {
System.out.printf(
// (5)
"Please note that no eggs will be served at %s, %02d:%02d.%n",
Meal.BREAKFAST, Meal.BREAKFAST.getHour(), Meal.BREAKFAST.getMins()
);
System.out.println("Meal times are as follows:");
Meal[] meals = Meal.values();
for (Meal meal : meals)
System.out.printf("%s served at %02d:%02d%n",
meal, meal.getHour(), meal.getMins()
);
// (6)
// (7)
Meal formalDinner = Meal.valueOf("DINNER");
// (8)
System.out.printf("Formal dress is required for %s at %02d:%02d.%n",
formalDinner, formalDinner.getHour(), formalDinner.getMins()
);
}
}
Output from the program:
Please note that no eggs will be served at BREAKFAST, 07:30.
Meal times are as follows:
BREAKFAST served at 07:30
LUNCH served at 12:15
DINNER served at 19:45
Formal dress is required for DINNER at 19:45.
Implicit Static Methods for Enum Types
All enum types implicitly have the following static methods, and methods with
these names cannot be declared in an enum type declaration:
static EnumTypeName[] values()
Returns an array containing the enum constants of this enum type, in the order
they are specified.
static EnumTypeName valueOf(String name)
Returns the enum constant with the specified name. An IllegalArgumentException is thrown if the specified name does not match the name of an enum constant. The specified name is not qualified with the enum type name.
The static method values() is called at (6) in Example 3.5 to create an array of enum
constants. This array is traversed in the for(:) loop at (7), printing the information
about each meal. The for(:) loop is discussed in Section 6.3, p. 220.
58
CHAPTER 3: DECLARATIONS
The static method valueOf() is called at (8) in Example 3.5 to retrieve the enum constant that has the specified name "DINNER". A printf statement is used to print the
information about the meal denoted by this enum constant.
Inherited Methods from the Enum Class
All enum types are subtypes of the java.lang.Enum class which provides the default
behavior. All enum types are comparable (Section 15.1, p. 765) and serializable
(Section 11.6, p. 510).
All enum types inherit the following final methods from the java.lang.Enum class,
and these methods can therefore not be overridden by an enum type:
protected final Object clone()
An instance of an enum type cannot be cloned (see Section 10.2, p. 424). The
method throws an CloneNotSupportedException.
final int compareTo(E o)
The natural order of the enum constants in an enum type is according to their
ordinal values (see the ordinal() method below). The compareTo() method in the
Comparable interface is discussed in Section 15.1, p. 765.
final boolean equals(Object other)
This method returns true if the specified object is equal to this enum constant
(Section 15.1, p. 751).
protected final void finalize()
An enum constant cannot be finalized, because this final method effectively
prevents enum types from implementing their own finalize() method (see
Section 9.4, p. 396).
final Class getDeclaringClass()
This method returns the Class object corresponding to this enum constant's
enum type (see Section 10.2, p. 424).
final int hashCode()
This method returns a hash code for this enum constant (see Section 15.1, p. 760).
final String name()
This method returns the name of this enum constant, exactly as declared in its
enum declaration.
final int ordinal()
This method returns the ordinal value of this enum constant (that is, its position
in its enum type declaration). The first enum constant is assigned an ordinal
value of zero. If the ordinal value of an enum constant is less than the ordinal
value of another enum constant of the same enum type, the former occurs
before the latter in the enum type declaration.
3.5: ENUMERATED TYPES
59
Note that the equality test implemented by the equals() method is based on reference equality (==) of the enum constants, not on value equality (Section 5.11, p. 193).
An enum type has a finite number of distinct objects. Comparing two enum references for equality means determining whether they store the reference value of the
same enum contant, i.e., whether the references are aliases. Thus, for any two enum
references meal1 and meal2, the expression meal1.equals(meal2) and meal1 == meal2
are equivalent.
The Enum class also overrides the toString() method from the Object class (see Section 10.2, p. 424). The toString() method returns the name of the enum constant,
but it is not final, and can be overridden by an enum type. Example 3.6 uses some
of the methods mentioned in this subsection.
Extending Enum Types: Constant-Specific Class Bodies
A review of subtyping (Section 7.1, p. 284), overriding (Section 7.2, p. 288), and anonymous classes (Section 8.5, p. 377) can be helpful before diving into this subsection.
Constant-specific class bodies define anonymous classes inside an enum type, i.e.,
they implicitly extend the enclosing enum type. The enum type Meal in Example
3.6 declares constant-specific class bodies for its constants. The following skeletal
code declares the constant-specific class body for the enum constant BREAKFAST:
BREAKFAST(7,30) {
// (1) Start of constant-specific class body
public double mealPrice(Day day) { // (2) Overriding abstract method
...
}
public String toString() {
// (3) Overriding method from the Enum
class
...
}
}
// (4) End of constant-specific class body
The constant-specific class body, as the name implies, is a class body that is specific
to a particular enum constant. As any class body, it is enclosed in braces, { }. It is
declared immediately after the enum constant and any constructor arguments. In
the code above, it starts at (1) and ends at (4). Like any class body, it can contain
member declarations. In the above case, the body contains two method declarations: an implementation of the method mealPrice() at (2) that overrides the
abstract method declaration at (7) in the enclosing enum supertype, and an implementation of the toString() method at (3) that overrides the one inherited by the
Meal enum type from the superclass java.lang.Enum.
The constant-specific class body is an anonymous class, i.e., a class with no name.
Each constant-specific class body defines a distinct, albeit anonymous, subtype of
the enclosing enum type. In the code above, the constant-specific class body
defines a subtype of the Meal enum type. It inherits members of the enclosing enum
supertype, that are not private, overridden, or hidden. When the enum type Meal
is loaded at runtime, this constant-specific class body is instantiated, and the reference value of the instance is assigned to the enum constant BREAKFAST. Note that the
60
CHAPTER 3: DECLARATIONS
type of the enum constant is Meal, which is the supertype of the anonymous subtype represented by the constant-specific class body. Since supertype references
can refer to subtype objects, the above assignment is legal.
Each enum constant overrides the abstract method mealPrice() declared in the
enclosing enum supertype, i.e., provides an implementation for the method. The
compiler will report an error if this is not the case. Although the enum type declaration specifies an abstract method, the enum type declaration is not declared
abstract—contrary to an abstract class. Given that the references meal and day are
of the enum types Meal and Day from Example 3.6, respectively, the method call
meal.mealPrice(day)
will execute the mealPrice() method from the constant-specific body of the enum
constant denoted by the reference meal.
Two constant-specific class bodies, associated with the enum constants BREAKFAST
and LUNCH, override the toString() method from the Enum class. Note that the
toString() method is not overridden in the Meal enum type, but in the anonymous
classes represented by two constant-specific class bodies. The third enum constant,
DINNER, relies on the toString() method inherited from the Enum class.
Constructors, abstract methods, and static methods cannot be declared in a constantspecific class body. Instance methods declared in constant-specific class bodies are
only accessible if they override methods in the enclosing enum supertype.
Example 3.6
Declaring Constant-Specific Class Bodies
// Filename: Day.java
public enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
// Filename: Meal.java
public enum Meal {
// Each enum constant defines a constant-specific class body
BREAKFAST(7,30) {
public double mealPrice(Day day) {
double breakfastPrice = 10.50;
if (day.equals(Day.SATURDAY) || day == Day.SUNDAY)
breakfastPrice *= 1.5;
return breakfastPrice;
}
public String toString() {
return "Breakfast";
}
},
LUNCH(12,15) {
public double mealPrice(Day day) {
double lunchPrice = 20.50;
switch (day) {
case SATURDAY: case SUNDAY:
// (1)
// (2)
// (3)
// (4)
// (5)
61
3.5: ENUMERATED TYPES
lunchPrice *= 2.0;
}
return lunchPrice;
}
public String toString() {
return "Lunch";
}
},
DINNER(19,45) {
public double mealPrice(Day day) {
// (6)
double dinnerPrice = 25.50;
if (day.compareTo(Day.SATURDAY) >= 0 && day.compareTo(Day.SUNDAY) <= 0)
dinnerPrice *= 2.5;
return dinnerPrice;
}
};
// Abstract method implemented in constant-specific class bodies.
abstract double mealPrice(Day day);
// (7)
// Enum constructor:
Meal(int hh, int mm) {
assert (hh >= 0 && hh <= 23): "Illegal hour.";
assert (mm >= 0 && mm <= 59): "Illegal mins.";
this.hh = hh;
this.mm = mm;
}
// Instance fields: Time for the meal.
private int hh;
private int mm;
// Instance methods:
public int getHour() { return this.hh; }
public int getMins() { return this.mm; }
}
// Filename: MealPrices.java
public class MealPrices {
public static void main(String[] args) {
System.out.printf(
"Please note that %s, %02d:%02d, on %s costs $%.2f.%n",
Meal.BREAKFAST.name(),
Meal.BREAKFAST.getHour(), Meal.BREAKFAST.getMins(),
Day.MONDAY,
Meal.BREAKFAST.mealPrice(Day.MONDAY)
);
// (8)
// (9)
// (10)
System.out.println("Meal prices on " + Day.SATURDAY + " are as follows:");
Meal[] meals = Meal.values();
for (Meal meal : meals)
System.out.printf(
"%s costs $%.2f.%n", meal, meal.mealPrice(Day.SATURDAY)
// (11)
62
CHAPTER 3: DECLARATIONS
);
}
}
Output from the program:
Please note that BREAKFAST, 07:30, on MONDAY costs $10.50.
Meal prices on SATURDAY are as follows:
Breakfast costs $15.75.
Lunch costs $41.00.
DINNER costs $63.75.
In Example 3.6, the mealPrice() method declaration at (2) uses both the equals()
method and the == operator to compare enum constants for equality. The mealPrice() method declaration at (5) uses enum constants in a switch statement (Section 6.2, p. 207). Note that the case labels in the switch statement are enum constant
names, without the enum type name. The mealPrice() method declaration at (6)
uses the compareTo() method to compare enum constants.
The main() method at (8) in Example 3.6 demonstrates calling the mealPrice()
method in the constant-specific class bodies. The mealPrice() method is called at
(10) and (11). Example 3.6 also illustrates the difference between the name() and the
toString() methods of the enum types. The name() method is called at (9), and the
toString() method is called at (10) and (11). The name() method always prints the
enum constant name exactly as it was declared. Which toString() method is executed depends on whether the toString() method in the Enum class is overridden.
Only the constant-specific class bodies of the enum constants BREAKFAST and LUNCH
override this method. The output from the program confirms this to be the case.
Declaring Typesafe Enums Revisited
An enum type can be declared as a top-level type. Enum types can also be nested,
but only within other static members, or other top-level type declarations (Section
8.2, p. 355). When nested, it is implicitly static, and can be declared with the keyword static. The following skeletal code shows the two enum types Day and Meal
declared as static members in the class MealPrices:
public class MealPrices {
public enum Day { /* ... */ }
// Static member
public static enum Meal { /* ... */ }
// Static member
public static void main(String[] args) { /* ... */ }
// Static method
}
An enum type cannot be explicitly extended using the extends clause. An enum
type is implicitly final, unless it contains constant-specific class bodies. If it
declares constant-specific class bodies, it is implicitly extended. No matter what, it
cannot be explicitly declared final.
63
3.5: ENUMERATED TYPES
An enum type cannot be declared abstract, regardless of whether each abstract
method is overridden in the constant-specific class body of every enum constant.
Like a class, an enum can implement interfaces.
public interface ITimeInfo {
public int getHour();
public int getMins();
}
public enum Meal implements ITimeInfo {
// ...
public int getHour() { return this.hh; }
public int getMins() { return this.mm; }
}
The Java Collections Framework provides a special purpose set implementation
(java.util.EnumSet) and a special purpose map implementation (java.util.EnumMap)
for use with enum types. These special purpose implementations provide better
performance for enum types than the general purpose counterparts, and are worth
checking out.
Review Questions
3.7
Which statements about the enum type are true?
Select the three correct answers.
(a) An enum type is a subclass of the abstract class java.lang.Enum, hence it is Comparable and Serializable.
(b) An enum type can implement interfaces.
(c) We can instantiate an enum type using the new operator.
(d) An enum type can define constructors.
(e) We can explicitly use the extend clause to extend an enum type.
(f) Enum types do not inherit members from the Object class.
3.8
What will be the result of attempting to compile and run the following code?
public enum Drill {
ATTENTION("Attention!"), EYES_RIGHT("Eyes right!"),
EYES_LEFT("Eyes left!"), AT_EASE("At ease!");
private String command;
Drill(String command) {
this.command = command;
}
public static void main(String[] args) {
System.out.println(ATTENTION);
System.out.println(AT_EASE);
}
}
// (1)
// (2)
64
CHAPTER 3: DECLARATIONS
Select the one correct answer.
(a) The code compiles, but reports a ClassNotFoundException when run, since an
enum type cannot be run as a standalone application.
(b) The compiler reports errors in (1) and (2), as the constants must be qualified
by the enum type name Drill.
(c) The compiler reports errors in (1) and (2), as the constants cannot be accessed
in a static context.
(d) The code compiles and prints:
ATTENTION
AT_EASE
(e) The code compiles and prints:
Attention!
At ease!
(f) None of the above.
3.9
What will be the result of compiling and running the following code?
import java.util.Arrays;
public enum Priority {
ONE(1) { public String toString() { return "LOW"; } },
TWO(2),
THREE(3) { public String toString() { return "NORMAL"; } },
FOUR(4),
FIVE(5) { public String toString() { return "HIGH"; } };
// (1)
// (2)
// (3)
private int pValue;
Priority(int pValue) {
this.pValue = pValue;
}
public static void main(String[] args) {
System.out.println(Arrays.toString(Priority.values()));
}
}
Select the one correct answer.
(a) The code compiles, but reports a ClassNotFoundException when run, since an
enum type cannot be run as a standalone application.
(b) The compiler reports syntax errors in (1), (2), and (3).
(c) The code compiles and prints:
[LOW, TWO, NORMAL, FOUR, HIGH]
(d) The code compiles and prints:
[ONE, TWO, THREE, FOUR, HIGH]
(e) None of the above.
65
3.5: ENUMERATED TYPES
3.10
Which statement about the following program is true?
public enum Scale {
GOOD('C'), BETTER('B'), BEST('A');
private char grade;
Scale(char grade) {
this.grade = grade;
}
abstract public char getGrade();
public static void main (String[] args) {
System.out.println (GOOD.getGrade());
}
// (1)
}
Select the one correct answer.
(a) Since the enum type declares an abstract method, the enum type must be
declared as abstract.
(b) The method call GOOD.getGrade() in (1) can be written without the enum type
name.
(c) An enum type cannot declare an abstract method.
(d) An enum type can declare an abstract method, but each enum constant must
provide an implementation.
3.11
What will be the result of compiling and running the following code?
public enum TrafficLight {
RED("Stop"), YELLOW("Caution"), GREEN("Go");
private String action;
TrafficLight(String action) {
this.action = action;
}
public static void main(String[] args) {
TrafficLight green = new TrafficLight("Go");
System.out.println(GREEN.equals(green));
}
}
Select the one correct answer.
(a)
(b)
(c)
(d)
The code will compile and print: true.
The code will compile and print: false.
The code will not compile, as an enum type cannot be instantiated.
An enum type does not have the equals() method.
66
CHAPTER 3: DECLARATIONS
3.12
Given the following program:
public enum Scale2 {
GOOD('C')
{ public char getGrade() { return grade; } },
BETTER('B') { public char getGrade() { return grade; } },
BEST('A')
{ public char getGrade() { return grade; } };
private char grade;
Scale2(char grade) {
this.grade = grade;
}
// (1) INSERT CODE HERE
public static void main (String[] args) {
System.out.println(GOOD.getGrade());
}
}
Which code, when inserted at (1), will make the program print C?
Select the two correct answers.
(a) public char getGrade() { return grade; }
(b) public int getGrade() { return grade; }
(c) abstract public int getGrade();
(d) abstract public char getGrade();
3.13
Given the following program:
enum Scale3 {
GOOD(Grade.C), BETTER(Grade.B), BEST(Grade.A);
enum Grade {A, B, C}
private Grade grade;
Scale3(Grade grade) {
this.grade = grade;
}
public Grade getGrade() { return grade; }
}
public class Scale3Client {
public static void main (String[] args) {
System.out.println(/* (1) INSERT CODE HERE */);
}
}
Which code, when inserted at (1), will make the program print true?
Select the four correct answers.
(a) Scale3.GOOD.getGrade() != Scale3.Grade.C
(b) Scale3.GOOD.getGrade().compareTo(Scale3.Grade.C) != 0
(c) Scale3.GOOD.getGrade().compareTo(Scale3.Grade.A) > 0
67
3.5: ENUMERATED TYPES
(d)
(e)
(f)
(g)
3.14
Scale3.GOOD.compareTo(Scale3.BEST) > 0
Scale3.GOOD.getGrade() instanceof Scale3.Grade
Scale3.GOOD instanceof Scale3
Scale3.GOOD.getGrade().toString().equals(Scale3.Grade.C.toString())
What will be the result of compiling and running the following code?
public enum Scale5 {
GOOD, BETTER, BEST;
public char getGrade() {
char grade = '\u0000';
switch(this){
case GOOD:
grade = 'C'; break;
case BETTER: grade = 'B'; break;
case BEST:
grade = 'A'; break;
}
return grade;
}
public static void main (String[] args) {
System.out.println(GOOD.getGrade());
}
}
Select the one correct answer.
(a) The program will not compile, as the switch expression is not compatible with
the case labels.
(b) The program will not compile, as enum constants cannot be used as case
labels.
(c) The case labels must be qualified with the enum type name.
(d) The program compiles, and when run, prints: C
(e) The program compiles, and when run, prints: GOOD
(f) None of the above.
3.15
Given the following code:
package p1;
enum March {LEFT, RIGHT}
public class Defence {
enum March {LEFT, RIGHT}
static enum Military {
INFANTRY, AIRFORCE;
enum March {LEFT, RIGHT}
}
class Secret {
enum March {LEFT, RIGHT}
}
static class Open {
enum March {LEFT, RIGHT}
}
public static void declareWar() {
// (1)
// (2)
// (3)
// (4)
// (5)
68
CHAPTER 3: DECLARATIONS
enum March {LEFT, RIGHT}
}
public void declarePeace() {
enum March {LEFT, RIGHT}
}
// (6)
// (7)
}
Which enum declarations are not legal?
Select the three correct answers.
(a)
(b)
(c)
(d)
(e)
(f)
(g)
3.16
The enum declaration at (1) is not legal.
The enum declaration at (2) is not legal.
The enum declaration at (3) is not legal.
The enum declaration at (4) is not legal.
The enum declaration at (5) is not legal.
The enum declaration at (6) is not legal.
The enum declaration at (7) is not legal.
Given the following code:
public enum Direction {
EAST, WEST, NORTH, SOUTH;
public static void main (String[] args) {
// (1) INSERT LOOP HERE
}
}
Which loops, when inserted independently at (1), will give the following output:
EAST
WEST
NORTH
SOUTH
Select the three correct answers.
(a) for (Direction d : Direction.values()) {
System.out.println(d);
}
(b) for (Direction d : Direction.values()) {
System.out.println(d.name());
}
(c) for (String name : Direction.names()) {
System.out.println(name);
}
(d) for (Direction d : java.util.Arrays.asList(Direction.values())) {
System.out.println(d);
}
(e) for (Direction d : java.util.Arrays.asList(Direction.class)) {
System.out.println(d);
};
69
3.6: ARRAYS
3.17
What will be the result of compiling and running the following code?
enum Rank {
FIRST(20), SECOND(0), THIRD(8);
Rank(int value) {
System.out.print(value);
}
}
public class EnumCreation {
public static void main (String[] args) {
System.out.println("\n" + Rank.values().length);
}
}
Select the one correct answer.
(a) The program will compile and print:
3
(b) The program will compile and print:
2008
3
(c) The program will compile. When run, it will print:
2008
and throw an exception.
(d) None of the above.
3.6 Arrays
An array is a data structure that defines an indexed collection of a fixed number of
homogeneous data elements. This means that all elements in the array have the
same data type. A position in the array is indicated by a non-negative integer value
called the index. An element at a given position in the array is accessed using the
index. The size of an array is fixed and cannot be changed.
In Java, arrays are objects. Arrays can be of primitive data types or reference types.
In the former case, all elements in the array are of a specific primitive data type. In
the latter case, all elements are references of a specific reference type. References in
the array can then denote objects of this reference type or its subtypes. Each array
object has a final field called length, which specifies the array size, i.e., the number
of elements the array can accommodate. The first element is always at index 0 and
the last element at index n-1, where n is the value of the length field in the array.
Simple arrays are one-dimensional arrays, that is, a simple list of values. Since arrays
can store reference values, the objects referenced can also be array objects. Thus,
multi-dimensional arrays are implemented as array of arrays.
70
CHAPTER 3: DECLARATIONS
Passing array references as parameters is discussed in Section 3.7. Type conversions for array references on assignment and on method invocation are discussed
in Section 7.7, p. 317.
Declaring Array Variables
A one-dimensional array variable declaration has either the following syntax:
[] ;
or
[];
where can be a primitive data type or a reference type. The array
variable has the type []. Note that the array size is not
specified. This means that the array variable can be assigned the reference value of an array of any length, as long as its elements have .
It is important to understand that the declaration does not actually create an array.
It only declares a reference that can refer to an array object.
int anIntArray[], oneInteger;
Pizza[] mediumPizzas, largePizzas;
The two declarations above declare anIntArray and mediumPizzas to be reference
variables that can refer to arrays of int values and arrays of Pizza objects, respectively. The variable largePizzas can denote an array of pizzas, but the variable
oneInteger cannot denote an array of int values—it is a simple variable of the type
int .
The [] notation can also be specified after a variable name to declare it as an array
variable, but then it only applies to this variable.
An array variable that is declared as a member of a class, but is not initialized to
any array, will be initialized to the default reference value null. This default initialization does not apply to local reference variables and, therefore, does not apply to
local array variables either (see Section 2.4, p. 33). This should not be confused with
initialization of the elements of an array during array construction.
Constructing an Array
An array can be constructed for a fixed number of elements of a specific type, using
the new operator. The reference value of the resulting array can be assigned to an
array variable of the corresponding type. The syntax of the array creation expression
is shown on the right-hand side of the following assignment statement:
= new [];
71
3.6: ARRAYS
The minimum value of is 0, in other words, zero-length arrays can be
constructed in Java. If the array size is negative, a NegativeArraySizeException is
thrown.
Given the following array declarations:
int anIntArray[], oneInteger;
Pizza[] mediumPizzas, largePizzas;
the arrays can be constructed as follows:
anIntArray
= new int[10];
mediumPizzas = new Pizza[5];
largePizzas = new Pizza[3];
// array for 10 integers
// array of 5 pizzas
// array of 3 pizzas
The array declaration and construction can be combined.
[] = new [];
Here the array type [] must be assignable to the array type [] (Section 7.7, p. 317). When the array is constructed, all its elements are initialized to the default value for . This is true for both member and
local arrays when they are constructed.
In all examples below, the code constructs the array, and the array elements are
implicitly initialized to their default value. For example, all elements of the array
anIntArray get the value 0, and all element of the array mediumPizzas get the value
null when the arrays are constructed.
int[] anIntArray = new int[10];
// Default element value: 0.
Pizza[] mediumPizzas = new Pizza[5];
// Default element value: null.
// Pizza class extends Object class
Object[] objArray = new Pizza[3];
// Default element value: null.
// Pizza class implements Eatable interface
Eatable[] eatables = new Pizza[2];
// Default element value: null.
The value of the field length in each array is set to the number of elements specified
during the construction of the array; for example, mediumPizzas.length has the
value 5.
Once an array has been constructed, its elements can also be explicitly initialized
individually; for example, in a loop. The examples in the rest of this section make
use of a loop to traverse the elements of an array for various purposes.
Initializing an Array
Java provides the means of declaring, constructing, and explicitly initializing an
array in one declaration statement:
[] = { };
72
CHAPTER 3: DECLARATIONS
This form of initialization applies to member as well as local arrays. The is a comma-separated list of zero or more expressions. Such an array
initialization block results in the construction and initialization of the array.
int[] anIntArray = {13, 49, 267, 15, 215};
The array anIntArray is declared as an array of ints. It is constructed to hold 5
elements (equal to the length of the list of expressions in the block), where the first
element is initialized to the value of the first expression (13), the second element to
the value of the second expression (49), and so on.
// Pizza class extends Object class
Object[] objArray = { new Pizza(), new Pizza(), null };
The array objArray is declared as an array of the Object class, constructed to hold
three elements. The initialization code sets the first two elements of the array to
refer to two Pizza objects, while the last element is initialized to the null reference.
Note that the number of objects created in the above declaration statement is actually three: the array object with three references and the two Pizza objects.
The expressions in the are evaluated from left to right, and the
array name obviously cannot occur in any of the expressions in the list. In the
examples above, the is terminated by the right curly bracket,
}, of the block. The list can also be legally terminated by a comma. The following
array has length two, and not three:
Topping[] pizzaToppings = { new Topping("cheese"), new Topping("tomato"), };
The declaration statement at (1) in the following code defines an array of four
String objects, while the declaration statement at (2) shows that a String object is
not the same as an array of char.
// Array with 4 String objects:
String[] pets = {"crocodiles", "elephants", "crocophants", "elediles"}; // (1)
// Array of 3 characters:
char[] charArray = {'a', 'h', 'a'};
// (2) Not the same as "aha".
Using an Array
The array object is referenced by the array name, but individual array elements are
accessed by specifying an index with the [] operator. The array element access
expression has the following syntax:
[]
Each individual element is treated as a simple variable of the element type. The
index is specified by the , which can be any expression that evaluates to a non-negative int value. Since the lower bound of an array is always 0,
the upper bound is one less than the array size, that is, .length-1. The
ith element in the array has index (i-1). At runtime, the index value is automatically checked to ensure that it is within the array index bounds. If the index value
73
3.6: ARRAYS
is less than 0, or greater than or equal to .length, an ArrayIndexOutOfBoundsException is thrown. A program can either check the index explicitly or catch
the exception (see Section 6.5, p. 235), but an illegal index is typically an indication
of a program bug.
In the array element access expression, the can be any expression that
returns a reference to an array. For example, the following expression returns the
character 'H' at index 1 in the character array returned by a call to the toCharArray()
method of the String class: "AHA".toCharArray()[1].
The array operator [] is used to declare array types (Topping[]), specify array size
(new Topping[3]), and to access array elements (toppings[1]). This operator is not
used when the array reference is manipulated, for example, in an array reference
assignment (see Section 7.9, p. 320), or when the array reference is passed as an
actual parameter in a method call (see Section 3.7, p. 86).
Example 3.7 shows traversal of arrays. The loop at (3) initializes the local array
trialArray declared at (2) five times with pseudo-random numbers (from 0.0 to
100.0), by calling the method randomize() declared at (5). The minimum value in the
array is found by calling the method findMinimum() declared at (6), and is stored in
the array storeMinimum declared at (1). The loop at (4) prints the minimum values
from the trials. The start value of the loop variable is initially set to 0. The loop condition tests whether the loop variable is less than the length of the array; this guarantees that the index will not go out of bounds.
Example 3.7
Using Arrays
public class Trials {
public static void main(String[] args) {
// Declare and construct the local arrays:
double[] storeMinimum = new double[5];
double[] trialArray = new double[15];
for (int i = 0; i < storeMinimum.length; ++i) {
// (1)
// (2)
// (3)
// Initialize the array.
randomize(trialArray);
// Find and store the minimum value.
storeMinimum[i] = findMinimum(trialArray);
}
// Print the minimum values:
for (int i = 0; i < storeMinimum.length; ++i)
System.out.printf("%.4f%n", storeMinimum[i]);
(4)
public static void randomize(double[] valArray) {
for (int i = 0; i < valArray.length; ++i)
valArray[i] = Math.random() * 100.0;
}
// (5)
}
74
CHAPTER 3: DECLARATIONS
public static double findMinimum(double[] valArray) {
// Assume the array has at least one element.
double minValue = valArray[0];
for (int i = 1; i < valArray.length; ++i)
minValue = Math.min(minValue, valArray[i]);
return minValue;
}
// (6)
}
Possible output from the program:
6.9330
2.7819
6.7427
18.0849
26.2462
Anonymous Arrays
As shown earlier in this section, the following declaration statement
[] = new []; // (1)
int[] intArray = new int[5];
can be used to construct arrays using an array creation expression. The size of the
array is specified in the array creation expression, which creates the array and initializes the array elements to their default values. On the other hand, the following
declaration statement
[] = { };
// (2)
int[] intArray = {3, 5, 2, 8, 6};
both creates the array and initializes the array elements to specific values given in the
array initializer block. However, the array initialization block is not an expression.
Java has another array creation expression, called anonymous array, which allows
the concept of the array creation expression from (1) and the array initializer block
from (2) to be combined, to create and initialize an array object:
new [] { }
new int[] {3, 5, 2, 8, 6}
The construct has enough information to create a nameless array of a specific type.
Neither the name of the array nor the size of the array is specified. The construct
returns the reference value of the newly-created array, which can be assigned to
references and passed as argument in method calls. In particular, the following two
examples of declaration statements are equivalent.
int[] intArray = {3, 5, 2, 8, 6};
// (1)
int[] intArray = new int[] {3, 5, 2, 8, 6}; // (2)
75
3.6: ARRAYS
In (1), an array initializer block is used to create and initialize the elements. In (2),
an anonymous array expression is used. It is tempting to use the array initialization block as an expression; for example, in an assignment statement, as a short cut
for assigning values to array elements in one go. However, this is illegal—instead,
an anonymous array expression should be used.
int[] daysInMonth;
daysInMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // Not ok.
daysInMonth = new int[] {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // ok.
The concept of anonymous arrays is similar to that of anonymous classes (see Section
8.5, p. 377): they both combine the definition and the creation of objects into one
operation.
In Example 3.8, an anonymous array is constructed at (1), and passed as a parameter to the static method findMinimum() defined at (2). Note that no array name or
array size is specified for the anonymous array.
Example 3.8
Using Anonymous Arrays
public class AnonArray {
public static void main(String[] args) {
System.out.println("Minimum value: " +
findMinimum(new int[] {3, 5, 2, 8, 6}));
}
public static int findMinimum(int[] dataSeq) {
// Assume the array has at least one element.
int min = dataSeq[0];
for (int index = 1; index < dataSeq.length; ++index)
if (dataSeq[index] < min)
min = dataSeq[index];
return min;
}
// (1)
// (2)
}
Output from the program:
Minimum value: 2
Multidimensional Arrays
Since an array element can be an object reference and arrays are objects, array
elements can themselves reference other arrays. In Java, an array of arrays can be
defined as follows:
[][]...[] ;
or
76
CHAPTER 3: DECLARATIONS
[][]...[];
In fact, the sequence of square bracket pairs, [], indicating the number of dimensions, can be distributed as a postfix to both the element type and the array name.
Arrays of arrays are also often called multidimensional arrays.
The following declarations are all equivalent:
int[][] mXnArray;
int[]
mXnArray[];
int
mXnArray[][];
// 2-dimensional array
// 2-dimensional array
// 2-dimensional array
It is customary to combine the declaration with the construction of the multidimensional array.
int[][] mXnArray = new int[4][5];
// 4 x 5 matrix of ints
The previous declaration constructs an array mXnArray of four elements, where each
element is an array (row) of 5 int values. The concept of rows and columns is often
used to describe the dimensions of a 2-dimensional array, which is often called a
matrix. However, such an interpretation is not dictated by the Java language.
Each row in the previous matrix is denoted by mXnArray[i], where 0 d i 4. Each
element in the ith row, mXnArray[i], is accessed by mXnArray[i][j], where 0 d j 5.
The number of rows is given by mXnArray.length, in this case 4, and the number of
values in the ith row is given by mXnArray[i].length, in this case 5 for all the rows,
where 0 d i 4.
Multidimensional arrays can also be constructed and explicitly initialized using
array initializer blocks discussed for simple arrays. Note that each row is an array
which uses an array initializer block to specify its values:
double[][] identityMatrix = {
{1.0, 0.0, 0.0, 0.0 }, // 1. row
{0.0, 1.0, 0.0, 0.0 }, // 2. row
{0.0, 0.0, 1.0, 0.0 }, // 3. row
{0.0, 0.0, 0.0, 1.0 } // 4. row
}; // 4 x 4 Floating-point matrix
Arrays in a multidimensional array need not have the same length, and are often
called ragged arrays. The array of arrays pizzaGalore in the code below will have five
rows, the first four rows have different lengths but the fifth row is left unconstructed.
Pizza[][] pizzaGalore = {
{ new Pizza(), null, new Pizza() },
{ null, new Pizza()},
new Pizza[1],
{},
null
};
//
//
//
//
//
1.
2.
3.
4.
5.
row
row
row
row
row
is
is
is
is
is
an array of 3 elements.
an array of 2 elements.
an array of 1 element.
an array of 0 elements.
not constructed.
When constructing multidimensional arrays with the new operator, the length of
the deeply nested arrays may be omitted. In which case, these arrays are left
unconstructed. For example, an array of arrays to represent a room on a floor in a
77
3.6: ARRAYS
hotel on a street in a city can have the type HotelRoom[][][][]. From left to right, the
square brackets represent indices for street, hotel, floor, and room, respectively.
This 4-dimensional array of arrays can be constructed piecemeal, starting with the
leftmost dimension and proceeding to the rightmost.
HotelRoom[][][][] rooms = new HotelRoom[10][5][][];
// Just streets and hotels.
The above declaration constructs the array of arrays rooms partially with ten streets,
where each street has five hotels. Floors and rooms can be added to a particular
hotel on a particular street:
rooms[0][0]
= new HotelRoom[3][]; // 3 floors in 1st. hotel on 1st. street.
rooms[0][0][0]
= new HotelRoom[8];
// 8 rooms on 1st. floor in this hotel.
rooms[0][0][0][0] = new HotelRoom();
// Initializes 1st. room on this floor.
The code below constructs an array of arrays matrix, where the first row has one
element, the second row has two elements, and the third row has three elements.
Note that the outer array is constructed first. The second dimension is constructed in a loop that constructs the array in each row. The elements in the multidimensional array will be implicitly initialized to the default double value (0.0D).
In Figure 3.2, the array of arrays matrix is depicted after the elements have been
explicitly initialized.
double[][] matrix = new double[3][];
// No. of rows.
for (int i = 0; i < matrix.length; ++i)
matrix[i] = new double[i + 1];
// Construct a row.
Two other ways of initializing such an array of arrays are shown below. The first
one uses array initializer blocks, and the second one uses an anonymous array of
arrays.
double[][] matrix2 = {
{0.0},
{0.0, 0.0},
{0.0, 0.0, 0.0}
}
//
//
//
//
Using array initializer blocks.
1. row
2. row
3. row
double[][] matrix3 = new double[][] { // Using an anonymous array of arrays.
{0.0},
// 1. row
{0.0, 0.0},
// 2. row
{0.0, 0.0, 0.0}
// 3. row
}
The type of the variable matrix is double[][], i.e., a two-dimensional array of double
values. The type of the variable matrix[i] (where 0 d i matrix.length) is double[],
i.e., a one-dimensional array of double values. The type of the variable matrix[i][j]
(where 0 dimatrix.length and 0 djmatrix[i].length) is double, i.e., a simple variable of type double.
Nested loops are a natural match for manipulating multidimensional arrays. In
Example 3.9, a rectangular 4 u 3 int matrix is declared and constructed at (1). The
program finds the minimum value in the matrix. The outer loop at (2) traverses the
rows (mXnArray[i], where 0 dimXnArray.length), and the inner loop at (3) traverses
78
CHAPTER 3: DECLARATIONS
Figure 3.2 Array of Arrays
matrix[0]:double[]
length = 1
matrix:double[][]
[0]
8.5
matrix[1]:double[]
length = 3
[0] :Ref(double[])
[1] :Ref(double[])
[2] :Ref(double[])
matrix[2]:double[]
length = 3
[0]
[1]
[2]
1.5
2.9
5.5
length = 2
[0]
[1]
6.3
4.4
matrix[2][1]
the elements in each row in turn (mXnArray[i][j], where 0 djmXnArray[i].length).
The outer loop is executed mXnArray.length times, or 4 times, and the inner loop is
executed (mXnArray.length) u (mXnArray[i].length), or 12 times, since all rows have
the same length, 3.
The for(:) loop also provides a safe and convenient way of traversing an array, and
ample examples are provided in Section 6.3, p. 220.
The Java standard library also provides the class java.util.Arrays that contains
various static methods for manipulating arrays, such as sorting and searching (see
Section 15.11, p. 842).
Example 3.9
Using Multidimensional Arrays
public class MultiArrays {
public static void main(String[] args) {
// Declare and construct the M X N matrix.
int[][] mXnArray = {
{16, 7, 12}, // 1. row
{ 9, 20, 18}, // 2. row
{14, 11, 5}, // 3. row
{ 8, 5, 10} // 4. row
}; // 4 x 3 int matrix
// (1)
// Find the minimum value in a M X N matrix:
int min = mXnArray[0][0];
for (int i = 0; i < mXnArray.length; ++i)
// (2)
// Find min in mXnArray[i], i.e. in the row given by index i:
for (int j = 0; j < mXnArray[i].length; ++j)
// (3)
min = Math.min(min, mXnArray[i][j]);
System.out.println("Minimum value: " + min);
}
}
79
3.6: ARRAYS
Output from the program:
Minimum value: 5
Review Questions
3.18
Given the following declaration, which expression returns the size of the array,
assuming the array has been initialized?
int[] array;
Select the one correct answer.
(a) array[].length()
(b) array.length()
(c) array[].length
(d) array.length
(e) array[].size()
(f) array.size()
3.19
Is it possible to create arrays of length zero?
Select the one correct answer.
(a)
(b)
(c)
(d)
Yes, you can create arrays of any type with length zero.
Yes, but only for primitive data types.
Yes, but only for arrays of reference types.
No, you cannot create zero-length arrays, but the main() method may be passed
a zero-length array of Strings when no program arguments are specified.
(e) No, it is not possible to create arrays of length zero in Java.
3.20
Which one of the following array declaration statements is not legal?
Select the one correct answer.
(a) int []a[] = new int [4][4];
(b) int a[][] = new int [4][4];
(c) int a[][] = new int [][4];
(d) int []a[] = new int [4][];
(e) int [][]a = new int [4][4];
3.21
Which of these array declaration statements are not legal?
Select the two correct answers.
(a) int[] i[] = { { 1, 2 }, { 1 }, {}, { 1, 2, 3 } };
(b) int i[] = new int[2] {1, 2};
(c) int i[][] = new int[][] { {1, 2, 3}, {4, 5, 6} };
(d) int i[][] = { { 1, 2 }, new int[ 2 ] };
80
CHAPTER 3: DECLARATIONS
(e) int i[4] = { 1, 2, 3, 4 };
3.22
What would be the result of compiling and running the following program?
// Filename: MyClass.java
class MyClass {
public static void main(String[] args) {
int size = 20;
int[] arr = new int[ size ];
for (int i = 0; i < size; ++i) {
System.out.println(arr[i]);
}
}
}
Select the one correct answer.
(a) The code will not compile, because the array type int[] is incorrect.
(b) The program will compile, but will throw an ArrayIndexOutOfBoundsException
when run.
(c) The program will compile and run without error, but will produce no output.
(d) The program will compile and run without error, and will print the numbers
0 through 19.
(e) The program will compile and run without error, and will print 0 twenty
times.
(f) The program will compile and run without error, and will print null twenty
times.
3.23
What would be the result of compiling and running the following program?
public class DefaultValuesTest {
int[] ia = new int[1];
boolean b;
int i;
Object o;
public static void main(String[] args) {
DefaultValuesTest instance = new DefaultValuesTest();
instance.print();
}
public void print() {
System.out.println(ia[0] + " " + b + " " + i + " " + o);
}
}
Select the one correct answer.
(a)
(b)
(c)
(d)
(e)
(f)
The program will fail to compile because of uninitialized variables.
The program will throw a java.lang.NullPointerException when run.
The program will print: 0 false NaN null.
The program will print: 0 false 0 null.
The program will print: null 0 0 null.
The program will print: null false 0 null.
81
3.7: PARAMETER PASSING
3.7 Parameter Passing
Objects communicate by calling methods on each other. A method call is used to
invoke a method on an object. Parameters in the method call provide one way of
exchanging information between the caller object and the callee object (which need
not be different).
Defining methods is discussed in Section 3.3, p. 44. Invoking static methods on
classes is discussed in Section 4.10, p. 147.
The syntax of a method call can be any one of the following: