A Programmer's Guide To Java SE 8 Oracle Certified Associate (OCA)

A%20Programmer's%20Guide%20to%20Java%20SE%208%20Oracle%20Certified%20Associate

User Manual: Pdf

Open the PDF directly: View PDF PDF.
Page Count: 2629

DownloadA Programmer's Guide To Java SE 8 Oracle Certified Associate (OCA)
Open PDF In BrowserView PDF
WOW! eBook
www.wowebook.org

About This E-Book
EPUB is an open, industry-standard format for e-books. However, support for EPUB
and its many features varies across reading devices and applications. Use your device or
app settings to customize the presentation to your liking. Settings that you can customize
often include font, font size, single or double column, landscape or portrait mode, and
figures that you can click or tap to enlarge. For additional information about the settings
and features on your reading device or app, visit the device manufacturer’s Web site.
Many titles include programming code or configuration examples. To optimize the
presentation of these elements, view the e-book in single-column, landscape mode and
adjust the font size to the smallest setting. In addition to presenting code and
configurations in the reflowable text format, we have included images of the code that
mimic the presentation found in the print book; therefore, where the reflowable format
may compromise the presentation of the code listing, you will see a “Click here to view
code image” link. Click the link to view the print-fidelity code image. To return to the
previous page viewed, click the Back button on your device or app.

WOW! eBook
www.wowebook.org

A Programmer’s Guide to Java® SE 8
Oracle Certified Associate (OCA)
A Comprehensive Primer
Khalid A. Mughal
Rolf W. Rasmussen
Boston • Columbus • Indianapolis • New York • San Francisco • Amsterdam • Cape Town
Dubai • London • Madrid • Milan • Munich • Paris • Montreal • Toronto • Delhi • Mexico
City
São Paulo • Sydney • Hong Kong • Seoul • Singapore • Taipei • Tokyo

WOW! eBook
www.wowebook.org

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.
For information about buying this title in bulk quantities, or for special sales opportunities
(which may include electronic versions; custom cover designs; and content particular to
your business, training goals, marketing focus, or branding interests), please contact our
corporate sales department at corpsales@pearsoned.com or (800) 382-3419.
For government sales inquiries, please contact governmentsales@pearsoned.com.
For questions about sales outside the U.S., please contact intlcs@pearson.com.
Visit us on the Web: informit.com/aw
Library of Congress Control Number: 2016937073
Copyright © 2017 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, request forms and the appropriate contacts within the Pearson Education
Global Rights & Permissions Department, please visit www.pearsoned.com/permissions/.
ISBN-13: 978-0-13-293021-5
ISBN-10: 0-13-293021-8
Text printed in the United States on recycled paper at RR Donnelley in Crawfordsville,
Indiana.
First printing, July 2016

WOW! eBook
www.wowebook.org

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.

WOW! eBook
www.wowebook.org

Contents Overview
Figures
Tables
Examples
Foreword
Preface
1 Basics of Java Programming
2 Language Fundamentals
3 Declarations
4 Access Control
5 Operators and Expressions
6 Control Flow
7 Object-Oriented Programming
8 Fundamental Classes
9 Object Lifetime
10 The ArrayList Class and Lambda Expressions
11 Date and Time
A Taking the Java SE 8 Programmer I Exam
B Exam Topics: Java SE 8 Programmer I
C Annotated Answers to Review Questions
D Solutions to Programming Exercises
E Mock Exam: Java SE 8 Programmer I
F Annotated Answers to Mock Exam I
Index

WOW! eBook
www.wowebook.org

Contents
Figures
Tables
Examples
Foreword
Preface
1 Basics of Java Programming
1.1 Introduction
1.2 Classes
Declaring Members: Fields and Methods
1.3 Objects
Class Instantiation, Reference Values, and References
Object Aliases
1.4 Instance Members
Invoking Methods
1.5 Static Members
1.6 Inheritance
1.7 Associations: Aggregation and Composition
1.8 Tenets of Java
Review Questions
1.9 Java Programs
1.10 Sample Java Application
Essential Elements of a Java Application
Compiling and Running an Application
1.11 Program Output
Formatted Output
1.12 The Java Ecosystem
Object-Oriented Paradigm
Interpreted: The JVM
Architecture-Neutral and Portable Bytecode
Simplicity
WOW! eBook
www.wowebook.org

Dynamic and Distributed
Robust and Secure
High Performance and Multithreaded
Review Questions
Chapter Summary
Programming Exercise
2 Language Fundamentals
2.1 Basic Language Elements
Lexical Tokens
Identifiers
Keywords
Separators
Literals
Integer Literals
Floating-Point Literals
Underscores in Numerical Literals
Boolean Literals
Character Literals
String Literals
Whitespace
Comments
Review Questions
2.2 Primitive Data Types
The Integer Types
The char Type
The Floating-Point Types
The boolean Type
Review Questions
2.3 Variable Declarations
Declaring and Initializing Variables
Reference Variables
2.4 Initial Values for Variables
WOW! eBook
www.wowebook.org

Default Values for Fields
Initializing Local Variables of Primitive Data Types
Initializing Local Reference Variables
Lifetime of Variables
Review Questions
Chapter Summary
Programming Exercise
3 Declarations
3.1 Class Declarations
3.2 Method Declarations
Statements
Instance Methods and the Object Reference this
Method Overloading
3.3 Constructors
The Default Constructor
Overloaded Constructors
Review Questions
3.4 Arrays
Declaring Array Variables
Constructing an Array
Initializing an Array
Using an Array
Anonymous Arrays
Multidimensional Arrays
Sorting Arrays
Searching Arrays
Review Questions
3.5 Parameter Passing
Passing Primitive Data Values
Passing Reference Values
Passing Arrays
Array Elements as Actual Parameters
WOW! eBook
www.wowebook.org

final Parameters
3.6 Variable Arity Methods
Calling a Variable Arity Method
Variable Arity and Fixed Arity Method Calls
3.7 The main() Method
Program Arguments
3.8 Enumerated Types
Declaring Type-safe Enums
Using Type-safe Enums
Selected Methods for Enum Types
Review Questions
Chapter Summary
Programming Exercise
4 Access Control
4.1 Java Source File Structure
4.2 Packages
Defining Packages
Using Packages
Compiling Code into Packages
Running Code from Packages
4.3 Searching for Classes
Review Questions
4.4 Scope Rules
Class Scope for Members
Block Scope for Local Variables
4.5 Accessibility Modifiers for Top-Level Type Declarations
4.6 Non-Accessibility Modifiers for Classes
abstract Classes
final Classes
Review Questions
4.7 Member Accessibility Modifiers
public Members
WOW! eBook
www.wowebook.org

protected Members
Default Accessibility for Members
private Members
Review Questions
4.8 Non-Accessibility Modifiers for Members
static Members
final Members
abstract Methods
synchronized Methods
native Methods
transient Fields
volatile Fields
Review Questions
Chapter Summary
Programming Exercise
5 Operators and Expressions
5.1 Conversions
Widening and Narrowing Primitive Conversions
Widening and Narrowing Reference Conversions
Boxing and Unboxing Conversions
Other Conversions
5.2 Type Conversion Contexts
Assignment Context
Method Invocation Context
Casting Context of the Unary Type Cast Operator: (type)
Numeric Promotion Context
5.3 Precedence and Associativity Rules for Operators
5.4 Evaluation Order of Operands
Left-Hand Operand Evaluation First
Operand Evaluation before Operation Execution
Left-to-Right Evaluation of Argument Lists
5.5 Representing Integers
WOW! eBook
www.wowebook.org

Calculating Two’s Complement
Converting Binary Numbers to Decimals
Converting Decimals to Binary Numbers
Relationships among Binary, Octal, and Hexadecimal Numbers
5.6 The Simple Assignment Operator =
Assigning Primitive Values
Assigning References
Multiple Assignments
Type Conversions in an Assignment Context
Review Questions
5.7 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
5.8 The Binary String Concatenation Operator +
5.9 Variable Increment and Decrement Operators: ++, -The Increment Operator ++
The Decrement Operator -Review Questions
5.10 Boolean Expressions
5.11 Relational Operators: <, <=, >, >=
5.12 Equality
Primitive Data Value Equality: ==, !=
Object Reference Equality: ==, !=
Object Value Equality
WOW! eBook
www.wowebook.org

5.13 Boolean Logical Operators: !, ^, &, |
Operand Evaluation for Boolean Logical Operators
Boolean Logical Compound Assignment Operators: &=, ^=, |=
5.14 Conditional Operators: &&, ||
Short-Circuit Evaluation
5.15 Integer Bitwise Operators: ~, &, |, ^
Bitwise Compound Assignment Operators: &=, ^=, |=
Review Questions
5.16 The Conditional Operator: ?:
5.17 Other Operators: new, [], instanceof, ->
Review Questions
Chapter Summary
Programming Exercise
6 Control Flow
6.1 Overview of Control Flow Statements
6.2 Selection Statements
The Simple if Statement
The if-else Statement
The switch Statement
Review Questions
6.3 Iteration Statements
The while Statement
The do-while Statement
The for(;;) Statement
The for(:) Statement
6.4 Transfer Statements
Labeled Statements
The break Statement
The continue Statement
The return Statement
Review Questions
WOW! eBook
www.wowebook.org

6.5 Stack-Based Execution and Exception Propagation
6.6 Exception Types
The Exception Class
The RuntimeException Class
The Error Class
Checked and Unchecked Exceptions
Defining Customized Exceptions
6.7 Exception Handling: try, catch, and finally
The try Block
The catch Clause
The finally Clause
6.8 The throw Statement
6.9 The throws Clause
Overriding the throws Clause
6.10 Advantages of Exception Handling
Review Questions
Chapter Summary
Programming Exercises
7 Object-Oriented Programming
7.1 Single Implementation Inheritance
Relationships: is-a and has-a
The Supertype–Subtype Relationship
7.2 Overriding Methods
Instance Method Overriding
Covariant return in Overriding Methods
Overriding versus Overloading
7.3 Hiding Members
Field Hiding
Static Method Hiding
7.4 The Object Reference super
Review Questions
WOW! eBook
www.wowebook.org

7.5 Chaining Constructors Using this() and super()
The this() Constructor Call
The super() Constructor Call
Review Questions
7.6 Interfaces
Defining Interfaces
Abstract Methods in Interfaces
Implementing Interfaces
Extending Interfaces
Interface References
Default Methods in Interfaces
Static Methods in Interfaces
Constants in Interfaces
Review Questions
7.7 Arrays and Subtyping
Arrays and Subtype Covariance
Array Store Check
7.8 Reference Values and Conversions
7.9 Reference Value Assignment Conversions
7.10 Method Invocation Conversions Involving References
Overloaded Method Resolution
7.11 Reference Casting and the instanceof Operator
The Cast Operator
The instanceof Operator
Review Questions
7.12 Polymorphism and Dynamic Method Lookup
7.13 Inheritance versus Aggregation
7.14 Basic Concepts in Object-Oriented Design
Encapsulation
Cohesion
Coupling
Review Questions
WOW! eBook
www.wowebook.org

Chapter Summary
Programming Exercises
8 Fundamental Classes
8.1 Overview of the java.lang Package
8.2 The Object Class
Review Questions
8.3 The Wrapper Classes
Common Wrapper Class Constructors
Common Wrapper Class Utility Methods
Numeric Wrapper Classes
The Character Class
The Boolean Class
Review Questions
8.4 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
Joining of CharSequence Objects
Searching for Characters and Substrings
Extracting Substrings
Converting Primitive Values and Objects to Strings
Formatted Strings
Review Questions
8.5 The StringBuilder and StringBuffer Classes
Thread-Safety
Mutability
Constructing String Builders
Reading and Changing Characters in String Builders
WOW! eBook
www.wowebook.org

Constructing Strings from String Builders
Appending, Inserting, and Deleting Characters in String Builders
Controlling String Builder Capacity
Review Questions
Chapter Summary
Programming Exercises
9 Object Lifetime
9.1 Garbage Collection
9.2 Reachable Objects
9.3 Facilitating Garbage Collection
9.4 Object Finalization
9.5 Finalizer Chaining
9.6 Invoking Garbage Collection Programmatically
Review Questions
9.7 Initializers
9.8 Field Initializer Expressions
Declaration Order of Initializer Expressions
9.9 Static Initializer Blocks
Declaration Order of Static Initializers
9.10 Instance Initializer Blocks
Declaration Order of Instance Initializers
9.11 Constructing Initial Object State
Review Questions
Chapter Summary
10 The ArrayList Class and Lambda Expressions
10.1 The ArrayList Class
Lists
Declaring References and Constructing ArrayLists
Modifying an ArrayList
Querying an ArrayList
Traversing an ArrayList
Converting an ArrayList to an Array
WOW! eBook
www.wowebook.org

Sorting an ArrayList
Arrays versus ArrayList
Review Questions
10.2 Lambda Expressions
Behavior Parameterization
Functional Interfaces
Defining Lambda Expressions
Type Checking and Execution of Lambda Expressions
Filtering Revisited: The Predicate Functional Interface
Review Questions
Chapter Summary
Programming Exercise
11 Date and Time
11.1 Basic Date and Time Concepts
11.2 Working with Temporal Classes
Creating Temporal Objects
Querying Temporal Objects
Comparing Temporal Objects
Creating Modified Copies of Temporal Objects
Temporal Arithmetic
11.3 Working with Periods
Creating Periods
Querying Periods
Creating Modified Copies of Periods
More Temporal Arithmetic
Review Questions
11.4 Formatting and Parsing
Default Formatters
Predefined Formatters
Localized Formatters
Customized Formatters
Review Questions
WOW! eBook
www.wowebook.org

Chapter Summary
Programming Exercise
A Taking the Java SE 8 Programmer I Exam
A.1 Preparing for the Exam
A.2 Registering for the Exam
Contact Information
Obtaining an Exam Voucher
Signing Up for the Test
After Taking the Exam
A.3 How the Exam Is Conducted
The Testing Locations
Utilizing the Allotted Time
The Exam Program
The Exam Result
A.4 The Questions
Assumptions about the Exam Questions
Types of Questions Asked
Types of Answers Expected
Topics Covered by the Questions
B Exam Topics: Java SE 8 Programmer I
C Annotated Answers to Review Questions
D Solutions to Programming Exercises
E Mock Exam: Java SE 8 Programmer I
F Annotated Answers to Mock Exam I
Index

WOW! eBook
www.wowebook.org

Figures
1.1 UML Notation for Classes
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 Associations
1.8 Class Diagram Depicting Composition
2.1 Primitive Data Types in Java
3.1 Array of Arrays
3.2 Parameter Passing: Primitive Data Values
3.3 Parameter Passing: Reference Values
3.4 Parameter Passing: Arrays
4.1 Java Source File Structure
4.2 Package Hierarchy
4.3 File Hierarchy
4.4 Searching for Classes
4.5 Block Scope
4.6 Public Accessibility for Members
4.7 Protected Accessibility for Members
4.8 Default Accessibility for Members
4.9 Private Accessibility for Members
5.1 Widening Primitive Conversions
5.2 Converting among Binary, Octal, and Hexadecimal Numbers
5.3 Overflow and Underflow in Floating-Point Arithmetic
5.4 Numeric Promotion in Arithmetic Expressions
6.1 Activity Diagram for if Statements
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
WOW! eBook
www.wowebook.org

6.5 Activity Diagram for the for Statement
6.6 Enhanced for Statement
6.7 Method Execution
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)
7.1 Inheritance Hierarchy
7.2 Inheritance Hierarchy for Example 7.2 and Example 7.3
7.3 Inheritance Hierarchies
7.4 Inheritance Relationships for Interface Constants
7.5 Reference Type Hierarchy: Arrays and Subtype Covariance
7.6 Type Hierarchy That Illustrates Polymorphism
7.7 Implementing Data Structures by Inheritance and Aggregation
8.1 Partial Inheritance Hierarchy in the java.lang Package
8.2 Converting Values among Primitive, Wrapper, and String Types
9.1 Memory Organization at Runtime
10.1 Partial ArrayList Inheritance Hierarchy

WOW! eBook
www.wowebook.org

Tables
1.1 Terminology for Class Members
1.2 Format Specifier Examples
2.1 Keywords in Java
2.2 Reserved Literals in Java
2.3 Reserved Keywords Not Currently in Use
2.4 Separators in Java
2.5 Examples of Literals
2.6 Examples of Decimal, Binary, Octal, and Hexadecimal Literals
2.7 Examples of Character Literals
2.8 Escape Sequences
2.9 Examples of Escape Sequence \ddd
2.10 Range of Integer Values
2.11 Range of Character Values
2.12 Range of Floating-Point Values
2.13 Boolean Values
2.14 Summary of Primitive Data Types
2.15 Default Values
3.1 Parameter Passing by Value
4.1 Accessing Members within a Class
4.2 Summary of Accessibility Modifiers for Top-Level Types
4.3 Summary of Non-Accessibility Modifiers for Classes
4.4 Summary of Accessibility Modifiers for Members
4.5 Summary of Non-Accessibility Modifiers for Members
5.1 Selected Conversion Contexts and Conversion Categories
5.2 Operator Summary
5.3 Representing Signed byte Values Using Two’s Complement
5.4 Examples of Truncated Values
5.5 Arithmetic Operators
5.6 Examples of Arithmetic Expression Evaluation
5.7 Arithmetic Compound Assignment Operators
WOW! eBook
www.wowebook.org

5.8 Relational Operators
5.9 Primitive Data Value Equality Operators
5.10 Reference Equality Operators
5.11 Truth Values for Boolean Logical Operators
5.12 Boolean Logical Compound Assignment Operators
5.13 Conditional Operators
5.14 Truth Values for Conditional Operators
5.15 Integer Bitwise Operators
5.16 Result Table for Bitwise Operators
5.17 Examples of Bitwise Operations
5.18 Bitwise Compound Assignment Operators
6.1 The return Statement
7.1 Overriding versus Overloading
7.2 Same Signature for Subclass and Superclass Method
7.3 Types and Values
10.1 Summary of Arrays versus ArrayLists
10.2 Selected Functional Interfaces from the java.util.function Package
11.1 Selected Common Method Prefix of the Temporal Classes
11.2 Selected ISO-Based Predefined Formatters for Date and Time
11.3 Format Styles for Date and Time
11.4 Combination of Format Styles and Localized Formatters
11.5 Selected Date/Time Pattern Letters

WOW! eBook
www.wowebook.org

Examples
1.1 Basic Elements of a Class Declaration
1.2 Static Members in Class Declaration
1.3 Defining a Subclass
1.4 An Application
1.5 Formatted Output
2.1 Default Values for Fields
2.2 Flagging Uninitialized Local Variables of Primitive Data Types
2.3 Flagging Uninitialized Local Reference Variables
3.1 Using the this Reference
3.2 Namespaces
3.3 Using Arrays
3.4 Using Anonymous Arrays
3.5 Using Multidimensional Arrays
3.6 Passing Primitive Values
3.7 Passing Reference Values
3.8 Passing Arrays
3.9 Array Elements as Primitive Data Values
3.10 Array Elements as Reference Values
3.11 Calling a Variable Arity Method
3.12 Passing Program Arguments
3.13 Using Enums
4.1 Defining Packages and Using Type Import
4.2 Single Static Import
4.3 Avoiding the Interface Constant Antipattern
4.4 Importing Enum Constants
4.5 Shadowing Static Import
4.6 Conflict in Importing Static Method with the Same Signature
4.7 Class Scope
4.8 Accessibility Modifiers for Classes and Interfaces
4.9 Abstract Classes
WOW! eBook
www.wowebook.org

4.10 Public Accessibility of Members
4.11 Accessing Static Members
4.12 Using final Modifier
4.13 Synchronized Methods
5.1 Evaluation Order of Operands and Arguments
5.2 Numeric Promotion in Arithmetic Expressions
5.3 Short-Circuit Evaluation Involving Conditional Operators
5.4 Bitwise Operations
6.1 Fall-Through in a switch Statement
6.2 Using break in a switch Statement
6.3 Nested switch Statement
6.4 Strings in switch Statement
6.5 Enums in switch Statement
6.6 The break Statement
6.7 Labeled break Statement
6.8 continue Statement
6.9 Labeled continue Statement
6.10 The return Statement
6.11 Method Execution
6.12 The try-catch Construct
6.13 Exception Propagation
6.14 The try-catch-finally Construct
6.15 The try-finally Construct
6.16 The finally Clause and the return Statement
6.17 Throwing Exceptions
6.18 The throws Clause
7.1 Extending Classes: Inheritance and Accessibility
7.2 Overriding, Overloading, and Hiding
7.3 Using the super Keyword
7.4 Constructor Overloading
7.5 The this() Constructor Call
WOW! eBook
www.wowebook.org

7.6 The super() Constructor Call
7.7 Implementing Interfaces
7.8 Default Methods in Interfaces
7.9 Default Methods and Multiple Inheritance
7.10 Static Methods in Interfaces
7.11 Constants in Interfaces
7.12 Inheriting Constants in Interfaces
7.13 Assigning and Passing Reference Values
7.14 Choosing the Most Specific Method (Simple Case)
7.15 Overloaded Method Resolution
7.16 The instanceof and Cast Operators
7.17 Using the instanceof Operator
7.18 Polymorphism and Dynamic Method Lookup
7.19 Implementing Data Structures by Inheritance and Aggregation
8.1 Methods in the Object Class
8.2 String Representation of Integers
8.3 String Construction and Equality
8.4 Reading Characters from a String
9.1 Garbage Collection Eligibility
9.2 Using Finalizers
9.3 Invoking Garbage Collection
9.4 Initializer Expression Order and Method Calls
9.5 Static Initializers and Forward References
9.6 Instance Initializers and Forward References
9.7 Object State Construction
9.8 Initialization Anomaly under Object State Construction
10.1 Using an ArrayList
10.2 Implementing Customized Methods for Filtering an ArrayList
10.3 Implementing an Interface for Filtering an ArrayList
10.4 User-Defined Functional Interface for Filtering an ArrayList
10.5 Using the Predicate Functional Interface for Filtering an ArrayList
10.6 Accessing Members in an Enclosing Object
WOW! eBook
www.wowebook.org

10.7 Accessing Local Variables in an Enclosing Method
10.8 Filtering an ArrayList
11.1 Creating Temporal Objects
11.2 Using Temporal Objects
11.3 Temporal Arithmetic
11.4 Period-Based Loop
11.5 More Temporal Arithmetic
11.6 Using Default Date and Time Formatters
11.7 Using Predefined Format Styles with Time-Based Values
11.8 Using Predefined Format Styles with Date-Based Values
11.9 Using Predefined Format Styles with Date and Time-Based Values
11.10 Formatting and Parsing with Letter Patterns
11.11 Formatting with Date/Time Letter Patterns

WOW! eBook
www.wowebook.org

Foreword
Java is now over twenty years old and the current release, JDK 8, despite its name, is
really the eleventh significant release of the platform. Whilst staying true to the original
ideas of the platform, there have been numerous developments adding a variety of features
to the language syntax as well as a huge number of APIs to the core class libraries. This
has enabled developers to become substantially more productive and has helped to
eliminate a variety of common situations that can easily result in bugs.
Java has continued to grow in popularity, which is in large part attributable to the
continued evolution of the platform, which keeps it fresh and addresses things that
developers want. According to some sources, there are more than nine million Java
programmers across the globe and this number looks set to continue to grow as most
universities use Java as a primary teaching language.
With so many Java programmers available to employers, how do they ensure that
candidates have the necessary skills to develop high-quality, reliable code? The answer is
certification: a standardized test of a developer’s knowledge about the wide variety of
features and techniques required to use Java efficiently and effectively. Originally
introduced by Sun Microsystems, the certification process and exam has been updated to
match the features of each release of Java. Oracle has continued this since acquiring Sun
in 2010.
Taking and passing the exams is not a simple task. To ensure that developers meet a high
standard of knowledge about Java, the candidate must demonstrate the ability to
understand a wide variety of programming techniques, a clear grasp of the Java syntax,
and a comprehensive knowledge of the standard class library APIs. With the release of
JDK 8, not only do Java developers need to understand the details of imperative and
object-oriented programming, they now need to have a grasp of functional programming
so they can effectively use the key new features: lambda expressions and the Streams API.
Which is why, ultimately, you need this book to help you prepare for the exam. The
authors have done a great job of presenting the material you need to know to pass the
exam in an approachable and easy-to-grasp way. The book starts with the fundamental
concepts and language syntax and works its way through what you need to know about
object-oriented programming before addressing more complex topics like generic types.
The latter part of the book addresses the most recent changes in JDK 8, that of lambda
expressions, the Streams API, and the new Date and Time API.
Having worked with Java almost since it was first released, both at Sun Microsystems and
then at Oracle Corporation, I think you will find this book an invaluable guide to help you
pass the Oracle Certified Associate Exam for Java SE 8. I wish you the best of luck!
—Simon Ritter
Deputy CTO, Azul Systems

WOW! eBook
www.wowebook.org

Preface
Writing This Book
Dear Reader, what you hold in your hand is the result of a meticulous high-tech operation
that took many months and required inspecting many parts, removing certain parts,
retrofitting some old parts, and adding many new parts to our previous book on an earlier
Java programmer certification exam, until we were completely satisfied with the result.
After you have read the book and passed the exam, we hope that you will appreciate the
TLC (tender loving care) that has gone into this operation. This is how it all came about.
Learning the names of Java certifications and the required exams is the first item on the
agenda. This book provides coverage for the exam to earn Oracle Certified Associate
(OCA), Java SE 8 Programmer Certification (also know as OCAJP8). The exam required
for this certification has the name Java SE 8 Programmer I Exam (Exam number 1Z0808). It is the first of two exams required to obtain Oracle Certified Professional (OCP),
Java SE 8 Programmer Certification (also known as OCPJP8). The second exam required
for this professional certification has the name Java SE 8 Programmer II Exam (Exam
number 1Z0-809). To reiterate, this book covers only the topics for the Java SE 8
Programmer I Exam that is required to obtain OCAJP8 certification.
A book on the new Java SE 8 certification was a long time coming. The mantle of Java
had been passed on to Oracle and Java 7 had hit the newsstand. We started out to write a
book to cover the topics for the two exams required to earn the Oracle Certified
Professional, Java SE 7 Programmer Certification. Soon after the release of Java 8,
Oracle announced the certification for Java SE 8. We decided to switch to the new version.
It was not a difficult decision to make. Java 8 marks a watershed when the language went
from being a pure object-oriented language to one that also incorporates features of
functional-style programming. As the saying goes, Java 8 changed the whole ballgame.
Java passed its twentieth birthday in 2015. Java 8, released a year earlier, represented a
significant milestone in its history. There was little reason to dwell on earlier versions.
The next decision concerned whether it would be best to provide coverage for the two
Java SE 8 Programmer Certification exams in one or two books. Pragmatic reasons
dictated two books. It would take far too long to complete a book that covered both
exams, mainly because the second exam was largely revamped and would require a lot of
new material. We decided to complete the book for the first exam. Once that decision was
made, our draft manuscript went back on the operating table.
Our approach to writing this book has not changed from the one we employed for our
previous books, mainly because it has proved successful. No stones were left unturned to
create this book, as we explain here.
The most noticeable changes in the exam for OCAJP8 are the inclusion of the core classes
in the new Date and Time API and the writing of predicates using lambda expressions.
The emphasis remains on analyzing code scenarios, rather than individual language
constructs. The exam continues to require actual experience with the language, not just
mere recitation of facts. We still claim that proficiency in the language is the key to
WOW! eBook
www.wowebook.org

success.
Since the exam emphasizes the core features of Java, this book provides in-depth coverage
of topics related to those features. As in our earlier books, supplementary topics are also
included to aid in mastering the exam topics.
This book is no different from our previous books in one other important aspect: It is a
one-stop guide, providing a mixture of theory and practice that enables readers to prepare
for the exam. It can be used to learn Java and to prepare for the exam. After the exam is
passed, it can also come in handy as a language guide.
Apart from including coverage of the new topics, our discussions of numerous topics from
the previous exam were extensively revised. All elements found in our previous books
(e.g., sections, examples, figures, tables, review questions, mock exam questions) were
closely scrutinized. New examples, figures, tables, and review questions were specifically
created for the new topics as well as for the revised ones. We continue to use UML
(Unified Modeling Language) extensively to illustrate concepts and language constructs,
and all numbered examples continue to be complete Java programs ready for
experimenting.
Feedback from readers regarding our previous books was invaluable in shaping this book.
Every question, suggestion, and comment received was deliberated upon. We are grateful
for every single email we have received over the years; that input proved invaluable in
improving this book.
Dear Reader, we wish you all the best should you decide to go down the path of Java
certification. May your loops terminate and your exceptions get caught!

About This Book
This book provides extensive coverage of the core features of the Java programming
language and its core application programming interface (API), with particular emphasis
on its syntax and usage. The book is primarily intended for professionals who want to
prepare for the Java SE 8 Programmer I 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 API.
The demand for well-trained and highly skilled Java programmers remains unabated.
Oracle offers many Java certifications that professionals can take to validate their skills
(see http://education.oracle.com). The certification provides members of the
IT industry with a standard to use when hiring such professionals, and it allows
professionals to turn their Java skills into credentials that are important for career
advancement.
The book provides extensive coverage of all the objectives defined by Oracle for the Java
SE 8 Programmer I exam. The exam objectives are selective, however, and do not include
many of the essential features of Java. This book covers many additional topics that every
Java programmer should master to be truly 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.
WOW! eBook
www.wowebook.org

This book is not a complete reference for Java, as it does not attempt to list every member
of every class from the Java SE platform API documentation. The purpose is not to
document the Java SE platform API. The emphasis is more on the Java programming
language features—their syntax and correct usage through code examples—and less on
teaching programming techniques.
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 This Book
The reader can choose a linear or a nonlinear route through the book, depending on his or
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 applications. For those preparing for
Java SE 8 Programmer I exam, the book has a separate appendix (Appendix A) providing
all the pertinent information on preparing for and taking the exam.
Cross-references are provided where necessary to indicate the relationships among the
various constructs of the language. To understand a language construct, all pertinent
details are provided where the construct is covered, but in addition, cross-references are
provided to indicate its relationship to other constructs. Sometimes it is necessary to
postpone discussion of certain aspects of a topic if they depend on concepts that have not
yet been covered in the book. A typical example is the consequences of object-oriented
programming concepts (for example, inheritance) on the member declarations that can
occur in a class. This approach can result in forward references in the initial chapters of
the book.
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 of the book:

WOW! eBook
www.wowebook.org

Programmer I Exam Objectives
0.1 Exam objectives are stated clearly at the beginning of every chapter.
0.2 The number in front of the objective identifies the exam objective, as defined
by Oracle, and can be found in Appendix B.
0.3 The objectives are organized into major sections, detailing the curriculum for
the exam.
0.4 The objectives for the Java SE 8 Programmer I exam are reproduced verbatim
in Appendix B, where for each section of the syllabus, references are included to
point the reader to relevant topics in the book.
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 objective is listed as a bullet at the beginning of the chapter.

Review Questions
Review questions are provided after every major topic to test and reinforce the material.
The review questions predominantly reflect the kind of multiple-choice questions that can
be asked on the actual exam. On the exam, the exact number of answers to choose for each
question is explicitly stated. The review questions in this book follow that practice.
Many questions on the actual exam contain code snippets with line numbers to indicate
that complete implementation is not provided, and that the necessary missing code to
compile and run the code snippets can be assumed. The review questions in this book
provide complete code implementations where possible, so that the code can be readily
compiled and run.
Annotated answers to the review questions are provided in Appendix C.

WOW! eBook
www.wowebook.org

Example 0.1

Example Source Code

We encourage readers to experiment with the code examples to reinforce the material from
the book. These examples can be downloaded from the book website (see p. xxxiv).
Java code is presented in a monospaced 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 singleline comment in the code. For example, in the following code snippet, the call to the
method doSomethingInteresting() at (1) does something interesting:
Click here to view code image
// …
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 in all uppercase letters.
Interface names begin with the prefix I, when it makes sense to distinguish them from
class names. Coding conventions are followed, except when we have had to deviate from
these conventions in the interest of space or clarity.

Chapter Summary
Each chapter concludes with a summary of the topics covered in the chapter, pointing out
the major concepts that were introduced.

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 Appendix D.

Mock Exam
The mock exam in Appendix E should be attempted when the reader feels confident about
the topics on the exam. It is highly recommended to read Appendix A before attempting
the mock exam, as Appendix A contains pertinent information about the questions to
expect on the actual exam. Each multiple-choice question in the mock exam explicitly
states how many answers are applicable for a given question, as is the case on the actual
exam. Annotated answers to the questions in the mock exam are provided in Appendix F.

Java SE Platform API Documentation
A vertical gray bar is used to highlight methods and fields found in the classes of
the Java SE Platform API.
Any explanation following the API information is also similarly highlighted.

WOW! eBook
www.wowebook.org

To obtain the maximum benefit from using this book in preparing for the Java SE 8
Programmer I exam, we strongly recommend installing the latest version (Release 8 or
newer) of the JDK and its accompanying API documentation. The book focuses solely on
Java 8, and does not acknowledge previous versions.

Book Website
This book is backed by a website providing auxiliary material:
www.ii.uib.no/~khalid/ocajp8/
The contents of the website include the following:
• Source code for all the examples in the book
• Solutions to the programming exercises in the book
• Annotated answers to the reviews questions in the book
• Annotated answers to the mock exam in the book
• Table of contents, sample chapter, and index from the book
• Errata for the book
• Links to miscellaneous Java resources (e.g., certification, discussion groups, tools)
Information about the Java Standard Edition (SE) and its documentation can be found at
the following website:
www.oracle.com/technetwork/java/javase/overview/index.html
The current authoritative technical reference for the Java programming language, The
Java® Language Specification: Java SE 8 Edition (also published by Addison-Wesley),
can be found at this website:
http://docs.oracle.com/javase/specs/index.html

Request for Feedback
Considerable effort has been made to ensure the accuracy of the content of this book. 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 not) for your purpose. Any feedback is valuable. The
principal author can be reached at the following email address:
khalid.mughal@uib.no
Register your copy of A Programmer’s Guide to Java® SE 8 Oracle Certified Associate
(OCA) at informit.com for convenient access to downloads, updates, and corrections as
they become available. To start the registration process, go to informit.com/register and
log in or create an account. Enter the product ISBN (9780132930215) and click Submit.
Once the process is complete, you will find any available bonus content under “Registered
WOW! eBook
www.wowebook.org

Products.”

About the Authors
Khalid A. Mughal
Khalid A. Mughal is an associate professor at the Department of Informatics at the
University of Bergen, Norway, where he has been responsible for designing and
implementing various courses in informatics. Over the years, he has taught programming
(primarily Java), software engineering (object-oriented system development), databases
(data modeling and database management systems), compiler techniques, web application
development, and software security courses. For 15 years, he was responsible for
developing and running web-based programming courses in Java, which were offered to
off-campus students. He has also given numerous courses and seminars at various levels
in object-oriented programming and system development using Java and Java-related
technologies, both at the University of Bergen and for the IT industry.
Mughal is the principal author and solely responsible for the contents of this book. He is
also the principal author of three books on previous versions of the Java programmer
certification—A Programmer’s Guide to Java™ SCJP Certification: A Comprehensive
Primer, Third Edition (0321556054); A Programmer’s Guide to Java™ Certification: A
Comprehensive Primer, Second Edition (0201728281); and A Programmer’s Guide to
Java™ Certification (0201596148)—and three introductory textbooks on programming in
Java: Java Actually: A First Course in Programming (1844804186); Java Actually: A
Comprehensive Primer in Java Programming (1844809331); and Java som første
programmeringsspråk/Java as First Programming Language, Third Edition
(8202245540).
Mughal currently works on security issues related to mobile data collection systems for
delivering health services in low- and middle-income countries.

Rolf W. Rasmussen
Rolf W. Rasmussen is a 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 was 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 exam in our
three previous books on Java programmer certification. Selected earlier content has been
utilized in this book. Together with Mughal, he is also a co-author of three introductory
textbooks on programming in Java.

WOW! eBook
www.wowebook.org

Acknowledgments
At Addison-Wesley, Greg Doench was again our editor, who effectively managed the
process of publishing this book. Regular dialog with him in recent months helped to keep
this project on track. Julie Nahil was the in-house contact at Addison-Wesley, who
professionally managed the production of the book. Anna Popick was the project editor,
who diligently handled the day-to-day project management for this book. Jill Hobbs did a
truly marvelous job copy editing the book. The folks at The CIP Group performed the
typesetting wizardry necessary to materialize the book. We would like to extend our
sincere thanks to Greg, Julie, Anna, Jill, the folks at The CIP Group, and all those behind
the scenes at Addison-Wesley, who helped to put this publication on the bookshelf.
For the technical review of the book, we were lucky that Roel De Nijs agreed to take on
the task. If you drop in on CodeRanch.com, you are bound to find him executing his
duties as a Sheriff, especially helping greenhorns find their bearing in the Java
certification corrals. He is a freelance Java developer with many IT companies as clients
and a multitude of Java certification accolades under his belt (SCJA, SCJP, SCJD,
OCAJP7). And not least, he is a Technical Reviewer Par Excellence. Without doubt, Roel
has a meticulous eye for detail. It is no exaggeration to say that his exhaustive feedback
has been invaluable in improving the quality of this book at all levels. Roel, you have our
most sincere thanks for your many excellent comments and suggestions, and above all, for
weeding out numerous pesky errors in the manuscript.
Over the years, we have also been lucky to have our own personal manuscript quality
controller: Marit Seljeflot Mughal. As diligently as with our previous books, she tirelessly
proofread several chapter drafts for this book, and put her finger on many unmentionable
mistakes and errors in the manuscript. Her valuable comments and suggestions have also
been instrumental in improving the quality of this book. If Marit, who has no IT
background, could make sense of the Java jargon we wrote, then we were confident our
readers would as well. Our most sincere thanks.
Great effort has been made to eliminate mistakes and errors in this book. We accept full
responsibility for any remaining oversights. We hope that when our Dear Readers find
any, they will bring them to our attention.
Many family occasions have been missed while working on this book. Without family
support, this book would not have seen the light of day. Khalid is ever grateful to his
family for their love, support, and understanding—but especially when he is working on a
book. Now that this book is out the door, he is off to play with his three grandchildren.
—Khalid A. Mughal
17 May 2016
Bergen, Norway

WOW! eBook
www.wowebook.org

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 to OOP, 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 by using abstractions. An
abstraction denotes the essential properties and behaviors of an object that differentiate it
from other objects. The essence of OOP is modeling abstractions, using classes and
objects. The hard part of this endeavor is finding the right abstraction.
A class denotes a category of objects, and acts as a blueprint for creating 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 that can store a value that represents a particular
WOW! eBook
www.wowebook.org

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 which services are provided, and the
implementation defines how these services are provided by the class. Clients (i.e., other
objects) need to know only the contract of an object, and not its implementation, 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.

Figure 1.1

UML Notation for Classes

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, rather than an
effective implementation of stacks. The character sequence // in the code indicates the
start of a single-line comment that can be used to document the code. All characters after
this sequence and to the end of the line are ignored by the compiler.
A class declaration contains member declarations that define the fields and the methods of
the objects the class represents. 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)
WOW! eBook
www.wowebook.org

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 at (2) with the same name as the
class. 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

Click here to view code image
// File: CharStack.java
public class CharStack {
// Class Declarations:

// Class name

// 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()
1; }
}

{
{
{
{
{

(2)

(3)
stackArray[++topOfStack] = element; }
return stackArray[topOfStack—]; }
return stackArray[topOfStack]; }
return topOfStack == -1; }
return topOfStack == stackArray.length -

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. A variable denotes a location in memory where a value can be stored.
An object reference (or simply reference) is a variable that can store a reference value.
WOW! eBook
www.wowebook.org

Thus a reference provides a handle to an object, as it can indirectly denote an object whose
reference value it holds. In Java, an object can be manipulated only via its reference value,
or equivalently by a reference that holds its reference value.
This setup for manipulating objects requires that a reference be declared, a class be
instantiated to create an object, and the reference value of the object created be stored in
the reference. These steps are accomplished by a declaration statement.
Click here to view code image
CharStack stack1 = new CharStack(10); // Stack length: 10 chars

In the preceding declaration statement, the left-hand side of the = operator declares that
stack1 is a reference of class CharStack. The reference stack1, therefore, can refer
to objects of class CharStack.
The right-hand side of the = operator creates an object of class CharStack. This step
involves using the new operator in conjunction with a call to a constructor of the class
(new CharStack(10)). The new operator creates an instance of the CharStack
class and returns the reference value of this instance. The = operator (called the
assignment operator) stores the reference value in the reference stack1 declared on the
left-hand side of the assignment operator. The reference stack1 can now be used to
manipulate the object whose reference value is stored in it.
Analogously, the following declaration statement declares the reference stack2 to be of
class CharStack, creates an object of class CharStack, and assigns its reference value
to the reference stack2:
Click here to view code image
CharStack stack2 = new CharStack(5);

// Stack length: 5 chars

Each object that is created has its own copy of the fields declared in the class declaration
in Example 1.1. That is, the two stack objects, referenced by stack1 and stack2, will
have their own stackArray and topOfStack fields.
The purpose of the constructor call on the right-hand side of the new operator is to
initialize the newly created object. In this particular case, for each new CharStack
object created using the new operator, the constructor at (2) in Example 1.1 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.
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 denoting the object is prefixed to the class name with a colon (:). If the
name of the reference is omitted, as in Figure 1.2b, this denotes an anonymous object.
Since objects in Java do not have names, but rather are denoted by references, a more
elaborate notation is shown in Figure 1.2c, where references of the CharStack class
explicitly refer to CharStack objects. In most cases, the more compact notation will
suffice.

WOW! eBook
www.wowebook.org

Figure 1.2

UML Notation for Objects

Object Aliases
Several references can refer to the same object, 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.
Click here to view code image
// 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 stack objects are created in the preceding code. Before the assignment at (1), the
situation is as depicted in Figure 1.3a. After the assignment at (1), the references stackA
and stackB will denote the same stack, as depicted in Figure 1.3b. The reference value
in stackA is assigned to stackB. The references 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 stackB before the assignment? When objects are no
longer in use, their memory is, if necessary, reclaimed and reallocated for other objects.
This process is called automatic garbage collection. Garbage collection in Java is taken
care of by the runtime environment.

WOW! eBook
www.wowebook.org

Figure 1.3

Aliases

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
constitute 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; such methods are
called instance methods. It is important to note that these methods pertain to each object of
the class. In contrast, the implementation of the methods 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 §1.5.

Invoking Methods
Objects communicate by message passing. As a consequence, 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 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 be passed 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.
Click here to view code image
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 given here invokes methods on the object denoted by the reference
WOW! eBook
www.wowebook.org

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 the 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.
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. Thus the following code in a client of the CharStack class will
not compile:
Click here to view code image
stack.topOfStack++;

// Compile-time error: topOfStack is not visible.

1.5 Static Members
In some cases, certain members should belong only to the class; that is, they should not be
part of any instance of the class. As an example, suppose 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, rather than to any specific 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 class, rather than 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, whose names are 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.

WOW! eBook
www.wowebook.org

Figure 1.4
Example 1.2

Class Diagram Showing Static Members of a Class

Static Members in Class Declaration

Click here to view code image
// File: 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()
1; }

{
{
{
{
{

stackArray[++topOfStack] = element; }
return stackArray[topOfStack—]; }
return stackArray[topOfStack]; }
return topOfStack == -1; }
return topOfStack == stackArray.length -

// 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 provides a summary of the terminology
used in defining members of a class.

WOW! eBook
www.wowebook.org

Figure 1.5

Table 1.1

Members of a Class

Terminology for Class Members

Clients can access static members in the class by using the class name. The following code
invokes the getInstanceCount() method in the class CharStack:
Click here to view code image
int count = CharStack.getInstanceCount(); // Class name to invoke static
method

Static members can also be accessed via object references, although doing so is considered
bad style:
WOW! eBook
www.wowebook.org

Click here to view code image
CharStack myStack = new CharStack(20);
int count = myStack.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 be accessed only by object references.

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 Engine, Axle, and GearBox, which make up a
vehicle.
Inheritance is illustrated here 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, along with 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 class
PrintableCharStack is a specialization of stacks of characters that can also print
their elements.

Figure 1.6

Class Diagram Depicting Inheritance Relationship

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:
Click here to view code image
class PrintableCharStack extends CharStack {
// (1)
// Instance method
public void printStackElements() {
// (2)
// … implementation of the method…
}
// The constructor calls the constructor of the superclass explicitly.
public PrintableCharStack(int capacity) { super(capacity); }
// (3)
}

WOW! eBook
www.wowebook.org

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 to support this
access. Implementation of the printStackElements() method is shown at (2). The
constructor of the PrintableCharStack class at (3) calls the constructor of the
superclass CharStack to initialize the stack properly.
Example 1.3

Defining a Subclass

Click here to view code image
// File: CharStack.java
public class CharStack {
// Instance variables
protected char[] stackArray;
protected int
topOfStack;

// The array that implements the stack
// The top of the stack

// The rest of the definition is the same as in Example 1.2.
}
// File: 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)
}

Objects of the PrintableCharStack class will respond just like the objects of the
CharStack class, but they also have the additional functionality defined in the subclass:
Click here to view code image
PrintableCharStack pcStack = new PrintableCharStack(3);
pcStack.push(‘H’);
pcStack.push(‘i’);
pcStack.push(‘!’);
pcStack.printStackElements();
// Prints “Hi!” on the terminal

1.7 Associations: Aggregation and Composition
An association defines a static relationship between objects of two classes. One such
association, called aggregation, expresses how an object uses other objects. Java supports
aggregation of objects by reference, since objects cannot contain other objects explicitly.
The aggregate object usually has fields that denote its constituent objects. A constituent
object can be shared with other aggregate objects.
WOW! eBook
www.wowebook.org

For example, an object of class Airplane might have a field that denotes an object of
class Pilot. This Pilot object of an Airplane object might be shared among other
aggregate objects (not necessarily Airplane objects) once the pilot has finished duty on
one airplane. In fact, the Pilot object can still be used even when its Airplane object
no longer exists. This aggregation relationship is depicted by the UML diagram in Figure
1.7 (empty diamond), showing that each object of the Airplane class has zero or one
object of class Pilot associated with it.

Figure 1.7

Class Diagram Depicting Associations

The aggregate association can be made stronger if the constituent objects cannot be shared
with other aggregate objects—for example, an Airplane object with two Wing objects.
The Wing objects cannot be shared and can exist only with their Airplane object; that
is, the Airplane object has ownership of its Wing objects. Conversely, the Wing
objects are a part of their Airplane object. This stronger aggregation association is
called composition and is depicted by the UML diagram in Figure 1.7 (filled diamond),
showing that each object of the Airplane class owns two objects of class Wing.
In the case of the CharStack class used in the earlier examples, each object of this class
has a field to store the reference value of an array object that holds the characters. It would
not be a good idea to share this array with other stack objects. The stack owns the array of
characters. The relationship between the stack object and its constituent array object can
be expressed by composition (Figure 1.8), showing that each object of the CharStack
class will own one array object of type char associated with it.

Figure 1.8

Class Diagram Depicting Composition

1.8 Tenets of Java
• Code in Java must be encapsulated in classes.
WOW! eBook
www.wowebook.org

• There are two kinds of values in Java: objects that are instances of classes or arrays,
and atomic values of primitive data types.
• References store reference values that denote objects, and are used to manipulate
objects.
• Objects in Java cannot contain other objects; they can only have references to other
objects.
• During execution, reclamation of objects that are no longer in use is managed by the
runtime environment.

Review Questions
1.1 Which statement is true about methods?
Select the one correct answer.
(a) A method is an implementation of an abstraction.
(b) A method is an attribute defining the property of a particular abstraction.
(c) A method is a category of objects.
(d) A method is an operation defining the behavior for a particular abstraction.
(e) A method is a blueprint for making operations.
1.2 Which statement is true about objects?
Select the one correct answer.
(a) An object is what classes are instantiated from.
(b) An object is an instance of a class.
(c) An object is a blueprint for creating concrete realization of abstractions.
(d) An object is a reference.
(e) An object is a variable.
1.3 Which is the first line of a constructor declaration in the following code?
Click here to view code image
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)
// (3)

{ return current; }
{ current = value; }
{ step = stepValue; }

// (4)
// (5)
// (6)

Select the one correct answer.
(a) (1)
WOW! eBook
www.wowebook.org

(b) (2)
(c) (3)
(d) (4)
(e) (5)
(f) (6)
1.4 Given that Thing is a class, how many objects and how many references are
created by the following code?
Thing item, stuff;
item = new Thing();
Thing entity = new Thing();

Select the two correct answers.
(a) One object is created.
(b) Two objects are created.
(c) Three objects are created.
(d) One reference is created.
(e) Two references are created.
(f) Three references are created.
1.5 Which statement is true about instance members?
Select the one correct answer.
(a) An instance member is also called a static member.
(b) An instance member is always a field.
(c) An instance member is never a method.
(d) An instance member belongs to an instance, not to the class as a whole.
(e) An instance member always represents an operation.
1.6 How do objects communicate in Java?
Select the one correct answer.
(a) They communicate by modifying each other’s fields.
(b) They communicate by modifying the static variables of each other’s classes.
(c) They communicate by calling each other’s instance methods.
(d) They communicate by calling static methods of each other’s classes.
1.7 Given the following code, which statements are true?
class A {
protected int value1;
}
class B extends A {
WOW! eBook
www.wowebook.org

int value2;
}

Select the two correct answers.
(a) Class A extends class B.
(b) Class B is the superclass of class A.
(c) Class A inherits from class B.
(d) Class B is a subclass of class A.
(e) Objects of class A have a field named value2.
(f) Objects of class B have a field named value1.
1.8 Given the following code, which statements express the most accurate association?
Click here to view code image
class Carriage { }
class TrainDriver { }
class Train {
private Carriage[] carriages;
private TrainDriver driver;
Train(TrainDriver trainDriver, int noOfCarriages) {
carriages = new Carriage[noOfCarriages];
driver = trainDriver;
}
void insertCarriage(Carriage newCarriage) { /* … */ }
}

Select the three correct answers.
(a) A Train object has an array of Carriage objects.
(b) A Train object owns an array of Carriage objects.
(c) A Train object owns Carriage objects.
(d) A Train object has a TrainDriver object.
(e) A Train object owns a TrainDriver object.
(f) A TrainDriver object is part of a Train object.
(g) An array of Carriage objects is part of a Train object.
(h) Carriage objects are part of a Train object.

WOW! eBook
www.wowebook.org

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 (Java Development Kit) 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. This rule implies that a source file
can contain at most one public class. If the source file contains a public class, the file
naming rule is enforced by the JDK.
Each class declaration in a source file is compiled into a separate class file, containing
Java bytecode. 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 SE platform API are already compiled, and the
JDK tools know where to find them.

1.10 Sample Java Application
The term application is just a synonym for a program, referring to source code that is
compiled and directly executed. 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.

WOW! eBook
www.wowebook.org

Example 1.4

An Application

Click here to view code image
// File: CharStack.java
public class CharStack {
// Same as in Example 1.2.
}
// File: 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”;
System.out.println(“Original string: ” + str);
int length = str.length();

// (1)

// 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: “);
// (2)
// 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();
// (3)
}
}

Output from the program:
Click here to view code image
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 must be
declared as shown in the following method stub:
Click here to view code image
public static void main(String[] args)
{ /* Implementation */ }

// Method header

The main() method has public accessibility—that is, it is accessible from any class.
The keyword static means the method belongs to the class. The keyword void
indicates that the method does not return any value. The parameter args is an array of
strings that can be used to pass information to the main() method when execution starts.

WOW! eBook
www.wowebook.org

Compiling and Running an Application
Java source files can be compiled using the Java compiler tool javac, which is part of
the JDK.
The source file Client.java contains the declaration of the Client class. This source
file can be compiled by giving the following command at the command line (the character
> is the command prompt):
>javac Client.java

This command creates the class file Client.class containing the Java bytecode 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. To run Example 1.4, give the following command on the command line:
Click here to view code image
>java Client
Original string: !no tis ot nuf era skcatS
Reversed string: Stacks are fun to sit on!

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.

1.11 Program Output
Data produced by a program is called output. This output can be sent to different devices.
The examples presented in this book send their output to a terminal window, where the
output is printed as line of characters with a cursor that advances as characters are printed.
A Java program can send its output to the terminal window using an object called standard
out. This object, which can be accessed using the public static final field out in the
System class, is an object of the class java.io.PrintStream that provides methods
for printing values. These methods convert values to their string representation and print
the resulting string.
Example 1.4 illustrates the process of printing values to the terminal window. The
argument in the call to the println() method at (1) is first evaluated, and the resulting
string is printed to the terminal window. This method always terminates the current line,
which results in the cursor being moved to the beginning of the next line:
Click here to view code image
System.out.println(“Original string: ” + str);

// (1)

The print() method at (2) prints its argument to the terminal window, but it does not
terminate the current line:
Click here to view code image
System.out.print(“Reversed string: “);
WOW! eBook
www.wowebook.org

// (2)

To terminate a line, without printing any values, we can use the no-argument println()
method:
Click here to view code image
System.out.println();

// (3)

Formatted Output
To have more control over how the values are printed, we can create formatted output. The
following method of the java.io.PrintStream class can be used for this purpose:
Click here to view code image
PrintStream printf(String format, Object… args)

The String parameter format specifies how formatting will be done. It contains
format specifications that determine how each subsequent value in the parameter
args will be formatted and printed. The parameter declaration Object… args
represents an array of zero or more arguments to be formatted and printed. The
resulting string from the formatting will be printed to the destination stream.
(System.out will print to the standard out object.)
Any error in the format string will result in a runtime exception.
The following call to the printf() method on the standard out object formats and prints
three values:
Click here to view code image
System.out.printf(“Formatted values|%5d|%8.3f|%5s|%n”, // Format string
2016, Math.PI, “Hi”);
// Values to format

At runtime, the following line is printed in the terminal window:
Click here to view code image
Formatted values| 2016|

3.142|

Hi|

The format string is the first argument in the method call. It contains four format
specifiers. The first three are %5d, %8.3f, and %5s, which specify how the three
arguments should be processed. The letter in the format specifier indicates the type of
value to format. Their location in the format string specifies where the textual
representation of the arguments should be inserted. The fourth format specifier, %n, is a
platform-specific line separator. Its occurrence causes the current line to be terminated,
with the cursor moving to the start of the next line. All other text in the format string is
fixed, including any other spaces or punctuation, and is printed verbatim.
In the preceding example, the first value is formatted according to the first format
specifier, the second value is formatted according to the second format specifier, and so
on. The | character has been used in the format string to show how many character
positions are taken up by the text representation of each value. The output shows that the
int value was written right-justified, spanning five character positions using the format
specifier %5d; the double value of Math.PI took up eight character positions and was
rounded to three decimal places using the format specifier %8.3f; and the String value
WOW! eBook
www.wowebook.org

was written right-justified, spanning five character positions using the format specifier
%5s. The format specifier %n terminates the current line. All other characters in the
format string are printed verbatim.
Table 1.2 shows examples of some selected format specifiers that can be used to format
values. Their usage is illustrated in Example 1.5, which prints a simple invoice.

Table 1.2

Format Specifier Examples

At the top of the invoice printed by Example 1.5, the company name is printed at (1) with
a format string that contains only fixed text. The date and time of day are printed on the
same line, with leading zeros at (2). A header is then printed at (3). The column names
WOW! eBook
www.wowebook.org

Item, Price, Quantity, and Amount are positioned appropriately with the format
specifications %-20s, %7s, %9s, and %8s, respectively.
Beneath the heading, the items purchased are printed at (5), (6), and (7) using the same
field widths as the column headings. The format for each item is defined by the format
string at (4). The item name is printed with the format string "%-20s", resulting in a 20character-wide string, left-justified. The item price and the total amount for each type of
item are printed as floating-point values using the format specifications %7.2f and
%8.2f, respectively. The quantity is printed as an integer using the format specification
%9d. The strings are left-justified, while all numbers are right-justified. The character s is
the conversion code for objects, while floating-point and integer values are printed using
the codes f and d, respectively.
At (8), the total cost of all items is printed using the format specification %8.2f. To
position this value correctly under the column Amount, we print the string "Total:"
using the format %-36s. The width of 36 characters is found by adding the width of the
first three columns of the invoice.

WOW! eBook
www.wowebook.org

Example 1.5

Formatted Output

Click here to view code image
// File: Invoice.java
public class Invoice {
public static void main(String[] args) {
System.out.printf(“Secure Data Inc.
”);
System.out.printf(“%02d/%02d/%04d, %02d:%02d%n%n”,
2, 13, 2016, 11, 5);
System.out.printf(“%-20s%7s%9s%8s%n”,
“Item”, “Price”, “Quantity”, “Amount”);
int quantity = 4;
double price = 120.25, amount = quantity*price, total = amount;
String itemFormat = “%-20s%7.2f%9d%8.2f%n”;
System.out.printf(itemFormat,
“FlashDrive, 250GB”, price, quantity, amount);
quantity = 2;
price = 455.0; amount = quantity*price; total = total + amount;
System.out.printf(itemFormat,
“Ultra HD, 4TB”, price, quantity, amount);
quantity = 1;
price = 8.50; amount = quantity*price; total = total + amount;
System.out.printf(itemFormat,
“USB 3.0 cable”, price, quantity, amount);
System.out.printf(“%-36s%8.2f%n”, “Total:”, total);

// (1)
// (2)
// (3)

// (4)
// (5)

// (6)

// (7)
// (8)

}
}

Output from the program:
Click here to view code image
Secure Data Inc.
Item
FlashDrive, 250GB
Ultra HD, 4TB
USB 3.0 cable
Total:

02/13/2016, 11:05
Price Quantity
120.25
4
455.00
2
8.50
1

Amount
481.00
910.00
8.50
1399.50

1.12 The Java Ecosystem
Since its initial release as Java Development Kit 1.0 (JDK 1.0) in 1996, the name Java has
become synonymous with a thriving ecosystem that provides the components and the tools
necessary for developing systems for today’s multicore world. Its diverse community,
comprising a multitude of volunteers, organizations, and corporations, continues to fuel its
evolution and grow with its success. Many free open-source technologies now exist that
are well proven, mature, and supported, making their adoption less daunting. These tools
and frameworks provide support for all phases of the software development life cycle and
beyond.
There are three major Java Platforms for the Java programming language:
• Java SE (Standard Edition)
• Java EE (Enterprise Edition)
WOW! eBook
www.wowebook.org

• Java ME (Micro Edition)
Each platform provides a hardware/operating system–specific JVM and an API
(application programming interface) to develop applications for that platform. The Java
SE platform provides the core functionality of the language. The Java EE platform is a
superset of the Java SE platform and, as the most extensive of the three platforms, targets
enterprise application development. The Java ME platform is a subset of the Java SE
platform, having the smallest footprint, and is suitable for developing mobile and
embedded applications. The upshot of this classification is that a Java program developed
for one Java platform will not necessary run under the JVM of another Java platform. The
JVM must be compatible with the Java platform that was used to develop the program.
The API and the tools for developing and running Java applications are bundled together
as JDK. Just the JVM and the runtime libraries are also bundled separately as JRE (Java
Runtime Environment).
The subject of this book is Java SE 8. We recommend installing the appropriate JDK for
Java SE 8 (or a newer version) depending on the hardware and operating system.
The rest of this section summarizes some of the factors that have contributed to the
evolution of Java from an object-oriented programming language to a full-fledged
ecosystem for developing all sorts of systems, including large-scale business systems and
embedded systems for portable computing devices. A lot of jargon is used in this section,
and might be difficult to understand at the first reading, but we recommend coming back
after working through the book to appreciate the factors that have contributed to the
success of Java.

Object-Oriented Paradigm
The Java programming language supports the object-oriented paradigm, in which the
properties of an object and its behavior are encapsulated in the object. The properties and
the behavior are represented by the fields and the methods of the object, respectively. The
objects communicate through method calls in a procedural manner. Encapsulation ensures
that objects are immune to tampering except when manipulated through their public
interface. Encapsulation exposes only what an object does and not how it does it, so that
its implementation can be changed with minimum impact on its clients. Some basic
concepts of object-oriented programming, such as inheritance and aggregation, were
introduced earlier in this chapter, and subsequent chapters will expand on this topic.
Above all, object-oriented system development promotes code reuse where existing
objects can be reused to implement new objects. It also facilitates implementation of large
systems, allowing their decomposition into manageable subsystems.

WOW! eBook
www.wowebook.org

Interpreted: The JVM
Java programs are compiled to bytecode that is interpreted by the JVM. Various
optimization technologies (e.g., just-in-time [JIT] delivery) have led to the JVM becoming
a lean and mean virtual machine with regard to performance, stability, and security. Many
other languages, such as Scala, Groovy, and Clojure, now compile to bytecode and
seamlessly execute on the JVM. The JVM has thus evolved into an ecosystem in its own
right.

Architecture-Neutral and Portable Bytecode
The often-cited slogan “Write once, run everywhere” is true only if a compatible JVM is
available for the hardware and software platform. In other words, to run Java SE
applications under Windows 10 on a 64-bit hardware architecture, the right JVM must be
installed. Fortunately, the JVM has been ported to run under most platforms and operative
systems that exist today, including hardware devices such as smart cards, mobile devices,
and home appliances.
The specification of the bytecode is architecture neutral, meaning it is independent of any
hardware architecture. It is executed by a readily available hardware and operating
system–specific JVM. The portability of the Java bytecode thus eases the burden of crossplatform system development.

Simplicity
Language design of Java has been driven by a desire to simplify the programming process.
Although Java borrows heavily from the C++ programming language, certain features that
were deemed problematic were not incorporated into its design. For example, Java does
not have a preprocessor, and it does not allow pointer handling, user-defined operator
overloading, or multiple class inheritance.
Java opted for automatic garbage collection, which frees the programmer from dealing
with many issues related to memory management, such as memory leaks.
However, the jury is still out on whether the syntax of nested classes or introduction of
wild cards for generics can be considered simple.

Dynamic and Distributed
The JVM can dynamically load class libraries from the local file system as well as from
machines on the network, when those libraries are needed at runtime. This feature
facilitates linking the code as and when necessary during the execution of a program. It is
also possible to query programmatically a class or an object at runtime about its metainformation, such as its methods and fields.
Java provides extensive support for networking to build distributed systems, where objects
are able to communicate across networks using various communication protocols and
technologies, such as Remote Method Invocation (RMI) and socket connections.

WOW! eBook
www.wowebook.org

Robust and Secure
Java promotes the development of reliable, robust, and secure systems. It is a strong
statically typed language: The compiler guarantees runtime execution if the code compiles
without errors. Elimination of pointers, runtime index checks for arrays and strings, and
automatic garbage collection are some of the features of Java that promote reliability. The
exception handling feature of Java is without doubt the main factor that facilitates the
development of robust systems.
Java provides multilevel protection from malicious code. The language does not allow
direct access to memory. A bytecode verifier determines whether any untrusted code
loaded in the JVM is safe. The sandbox model is used to confine and execute any
untrusted code, limiting the damage that such code can cause. These features, among
others, are provided by a comprehensive Java security model to ensure that application
code executes securely in the JVM.

High Performance and Multithreaded
The performance of Java programs has improved significantly with various optimizations
that are applied to the bytecode at runtime by the JVM. The JIT feature monitors the
program at runtime to identify performance-critical bytecode (called hotspots) that can be
optimized. Such code is usually translated to machine code to boost performance. The
performance achieved by the JVM is a balance between native code execution and
interpretation of fully scripted languages, which fortunately is adequate for many
applications.
Java has always provided high-level support for multithreading, allowing multiple threads
of execution to perform different tasks concurrently in an application. It has risen to the
new challenges that have emerged in recent years to harness the increased computing
power made available by multicore architectures. Functional programming, in which
computation is treated as side-effects–free evaluation of functions, is seen as a boon to
meet these challenges. Java 8 brings elements of functional-style programming into the
language, providing language constructs (lambda expressions and functional interfaces)
and API support (through its Fork & Join Framework and Stream API) to efficiently
utilize the many cores to process large amounts of data in parallel.

Review Questions
1.9 Which command from the JDK should be used to compile the following source
code contained in a file named SmallProg.java?
Click here to view code image
public class SmallProg {
public static void main(String[] args) { System.out.println(“Good
luck!”); }
}

Select the one correct answer.
(a) java SmallProg
WOW! eBook
www.wowebook.org

(b) javac SmallProg
(c) java SmallProg.java
(d) javac SmallProg.java
(e) java SmallProg main
1.10 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()
1.11 Which statement is true about Java?
Select the one correct answer.
(a) A Java program can be executed by any JVM.
(b) Java bytecode cannot be translated to machine code.
(c) Only Java programs can be executed by a JVM.
(d) A Java program can create and destroy objects.
(e) None of the above

Chapter Summary
The following topics were covered in this chapter:
• Essential elements of a Java application
• Accessing object fields and calling methods
• Compiling and running Java applications
• Formatting and printing values to the terminal window
• Basic terminology and concepts in OOP, and how these concepts are supported in
Java
• Factors and features of the Java ecosystem that have contributed to its evolution and
success

WOW! eBook
www.wowebook.org

Programming Exercise
1.1 Modify the Client class 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 behavior-wise any different from Example 1.4?

WOW! eBook
www.wowebook.org

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 always be a
letter, as explained later.
Since Java programs are written in the Unicode character set (p. 32), characters allowed in
identifier names are interpreted according to this character set. Use of the Unicode
character set opens up the possibility of writing identifier names in many writing scripts
used around the world. As one would expect, the characters A-Z and a-z are letters, and
characters from 0-9 are digits. A connecting punctuation character (such as underscore
_) and any currency symbol (such as $, ¢, ¥, or £) are also allowed as letters in identifier
names, but these characters should be used judiciously.
WOW! eBook
www.wowebook.org

Identifiers in Java are case sensitive. For example, price and Price are two different
identifiers.
Examples of Legal Identifiers
Click here to view code image
number, Number, sum_$, bingo, $$_100, _007, mål, grüß

Examples of Illegal Identifiers
48chevy, all@hands, grand-sum

The name 48chevy is not a legal identifier because 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 not a
legal character in an identifier, but it is a legal operator; thus grand-sum 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 Java keywords are lowercase, and incorrect usage results in
compile-time errors.
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 (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

Reserved Literals in Java

WOW! eBook
www.wowebook.org

Table 2.3

Reserved Keywords Not Currently in Use

Separators
Separators (also known as punctuators) are tokens that have meaning depending on the
context in which they are used; they aid the compiler in performing syntax and semantic
analysis of a program (Table 2.4). Depending on the context, brackets ([]), parentheses
(()), and the dot operator (.) can also be interpreted as operators (§5.3, p. 150). See the
index entries for these separators for more details.

Table 2.4

Separators in Java

Literals
A literal denotes a constant value; in other words, the value that a literal represents
remains unchanged in the program. Literals represent numerical (integer or floatingpoint), character, boolean, or string values. In addition, the literal null represents the null
reference. Table 2.5 shows examples of literals in Java.

Table 2.5

Examples of Literals

Integer Literals
Integer data types comprise the following primitive data types: int, long, byte, and
short (§2.2, p. 37).
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. The suffix L is often preferred
because the suffix l and the digit 1 can be hard to distinguish. 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 be specified in the binary
(base 2, digits 0-1), octal (base 8, digits 0-7), and hexadecimal (base 16, digits 0-9 and
a-f) number systems. The digits a to f in the hexadecimal system correspond to decimal
values 10 to 15. Binary, octal, and hexadecimal numbers are specified with 0b (or 0B),
WOW! eBook
www.wowebook.org

0, and 0x (or 0X) as the base or radix prefix, respectively. Examples of decimal, binary,
octal, and hexadecimal literals are shown in Table 2.6. 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 the
number system (e.g., -0b1011010, -0132, or -0X5A). Integer representation is
discussed in §5.5, p. 154.

Table 2.6

Examples of Decimal, Binary, Octal, and Hexadecimal Literals

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).

WOW! eBook
www.wowebook.org

Examples of double Literals
Click here to view code image
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. Also, for the examples of float literals presented here, the suffix F is
mandatory; if it was omitted, they would be interpreted as double literals.

Underscores in Numerical Literals
The underscore character (_) can be used to improve the readability of numerical literals
in the source code. Any number of underscores can be inserted between the digits that
make up the numerical literal. This rules out underscores adjacent to the sign (+, -), the
radix prefix (0b, 0B, 0x, 0X), the decimal point (.), the exponent (e, E), and the data
type suffix (l, L, d, D, f, F), as well as before the first digit and after the last digit. Note
that octal radix prefix 0 is part of the definition of an octal literal and is therefore
considered the first digit of an octal literal.
Underscores in identifiers are treated as letters. For example, the names _XXL and _XXL_
are two distinct legal identifiers. In contrast, underscores are used as a notational
convenience for numerical literals, being ignored by the compiler when used in such
literals. In other words, a numerical literal can be specified in the source code using
underscores between digits, such that 2_0_1_5 and 20__15 represent the same
numerical literal 2015 in source code.
Examples of Legal Use of Underscores in Numerical Literals
Click here to view code image
0b0111_1111_1111_1111_1111_1111_1111_1111
0_377_777_777
0xff_ff_ff_ff
-123_456.00
1_2.345_678e1_2
2009__08__13
49_03_01d

Examples of Illegal Use of Underscores in Numerical Literals
Click here to view code image
_0_b_01111111111111111111111111111111_
_0377777777_
_0_x_ffffffff_
+_123456_._00_
_12_._345678_e_12_
_20090813_
_490301_d_

WOW! eBook
www.wowebook.org

Boolean Literals
The primitive data type boolean represents the truth values true and false that are
denoted by the reserved literals true and 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.7, note that
digits (0 to 9), uppercase letters (A to Z), and lowercase letters (a to z) have contiguous
Unicode values. A Unicode character can always be specified as a four-digit hexadecimal
number (i.e., 16 bits) with the prefix \u.

Table 2.7

Examples of Character Literals

Escape Sequences
Certain escape sequences define special characters, as shown in Table 2.8. 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.

WOW! eBook
www.wowebook.org

Table 2.8

Escape Sequences

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.9. The number of
digits must be three or fewer, and the octal value cannot exceed \377; in other words,
only the first 256 characters can be specified with this notation.

Table 2.9

Examples of Escape Sequence \ddd

String Literals
A string literal is a sequence of characters that must be enclosed in double quotes and
must occur on a single line. All string literals are objects of the class String (§8.4, p.
357).
Escape sequences as well as Unicode values can appear in string literals:
Click here to view code image
“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
WOW! eBook
www.wowebook.org

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. The expression in (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:
Click here to view code image
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.

Whitespace
A whitespace is a sequence of spaces, tabs, form feeds, and line terminator characters in a
Java source file. Line terminators include the 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—
that is, broken into a stream of tokens for further analysis. Separators and operators help to
distinguish tokens, but sometimes whitespace has to be inserted explicitly as a separator.
For example, the identifier classRoom will be interpreted as a single token, unless
whitespace is inserted to distinguish the keyword class from the identifier Room.
Whitespace aids not only in separating tokens, but also in formatting the program so that it
is easy to read. The compiler ignores the whitespace 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 that can be used 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.
Click here to view code image
// This comment ends at the end of this line.
int age;
// From comment-start sequence to the end of the line is a
comment.
WOW! eBook
www.wowebook.org

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, so they are ignored. This means that trying to
nest multiple-line comments will result in a compile-time error:
Click here to view code image
/* 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.
Documentation Comment
A documentation comment is a special-purpose multiple-line 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
*/:
Click here to view code image
/**
* This class implements a gizmo.
* @author K.A.M.
* @version 4.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
WOW! eBook
www.wowebook.org

(f) _8to5
2.2 Which of the following are not legal literals in Java?
Select the four correct answers.
(a) 0Xbad
(b) 0B_101_101
(c) 09
(d) +_825
(e) 1_2e4f
(f) '\x'
(g) "what\'s your fancy?"
2.3 Which statement is true?
Select the one correct answer.
(a) new and delete are keywords in the Java language.
(b) try, catch, and thrown are keywords in the Java language.
(c) static, unsigned, and long are keywords in the Java language.
(d) exit, class, and while are keywords in the Java language.
(e) return, goto, and default are keywords in the Java language.
(f) for, while, and next are keywords in the Java language.
2.4 Which of the following is not a legal comment in Java?
Select the one correct answer.
(a) /* // */
(b) /* */ //
(c) // /* */
(d) /* /* */
(e) /* /* */ */
(f) // //

2.2 Primitive Data Types
Figure 2.1 gives an overview of the primitive data types in Java.

WOW! eBook
www.wowebook.org

Figure 2.1

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
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 (Chapter 5, p. 143).
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 §8.3, p. 346.

The Integer Types
The integer data types are byte, short, int, and long (Table 2.10). Their values are
signed integers represented by two’s complement (§5.5, p. 155).

Table 2.10

The

Range of Integer Values

Type

The data type char represents characters (Table 2.11). Their values are unsigned integers
that denote all of the 65536 (216) characters in the 16-bit Unicode character set. This set
includes letters, digits, and special characters.
WOW! eBook
www.wowebook.org

Table 2.11

Range of Character Values

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
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.12 shows the range of values for positive floating-point numbers, but these apply
equally to negative floating-point numbers with the minus sign (-) as a prefix. Zero can be
either 0.0 or -0.0.

Table 2.12

Range of Floating-Point Values

Since the size for representation is a finite number of bits, certain floating-point numbers
can be represented only 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 to
represent floating-point numbers.

The

Type

The data type boolean represents the two logical values denoted by the literals true
and false (Table 2.13).

Table 2.13

Boolean Values

Boolean values are produced by all relational (§5.11, p. 180), conditional (§5.14, p. 186),
and boolean logical operators (§5.13, p. 184), and are primarily used to govern the flow
of control during program execution.
Table 2.14 summarizes the pertinent facts about the primitive data types: their width or
WOW! eBook
www.wowebook.org

size, which indicates the number of 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 (§8.3, p. 346).

Table 2.14

Summary of Primitive Data Types

Review Questions
2.5 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.6 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.7 Which integral type in Java has the exact range from -2147483648 (i.e., -231) to
WOW! eBook
www.wowebook.org

2147483647 (i.e., 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 store only 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 follow:
Click here to view code image
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.

The first declaration is equivalent to the following three declarations:
char a;
char b;
char c;

A declaration can also be combined with an initialization expression to specify an
appropriate initial value for the variable. Such declarations are called declaration
statements.
Click here to view code image
int i = 10,
j = 0b101;
long big = 2147483648L;
value.

// i is an int variable with initial value 10.
// j is an int variable with initial value 5.
// big is a long variable with specified initial

Reference Variables
A 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, an interface
name, or an enum type) declares a reference variable. Analogous to the declaration of
variables of primitive data types, the simplest form of reference variable declaration
WOW! eBook
www.wowebook.org

specifies the name and the reference type only. The declaration determines which 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.
Click here to view code image
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 preceding declarations do not create any objects of class
Pizza or Hamburger. Rather, they simply create variables that can store reference
values of objects of the specified classes.
A declaration can also be combined with an initializer expression to create an object
whose reference value can be assigned to the reference variable:
Click here to view code image
Pizza yummyPizza = new Pizza(“Hot&Spicy”); // Declaration statement

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.

2.4 Initial Values for Variables
This section discusses what value, if any, is assigned to a variable when no explicit initial
value is provided in the declaration.

Default Values for Fields
Default values for fields of primitive data types and reference types are listed in Table
2.15. The value assigned depends on the type of the field.

Table 2.15

Default Values

If no explicit initialization is provided for a static variable, 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, it is initialized with the default value of its type when the class is
WOW! eBook
www.wowebook.org

instantiated. The fields of reference types are always initialized with the null reference
value if no initialization is provided.
Example 2.1 illustrates the 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

Click here to view code image
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:
System.out.println(“Instance variable noOfWatts:
System.out.println(“Instance variable indicator:
System.out.println(“Instance variable location:
}

”
”
”
”

+
+
+
+

Light.counter);
bulb.noOfWatts);
bulb.indicator);
bulb.location);

}

Output from the program:
Click here to view code image
Static variable counter:
Instance variable noOfWatts:
Instance variable indicator:
Instance variable location:

0
100
false
null

Initializing Local Variables of Primitive Data Types
Local variables are variables that are declared in methods, constructors, and blocks
(Chapter 3, p. 47). They are not initialized implicitly when they are allocated memory at
method invocation—that is, when the execution of a method begins. The same applies to
local variables in constructors and blocks. Local variables must be explicitly initialized
before being used. The compiler will report an error only if an attempt is made to use an
uninitialized local variable.

WOW! eBook
www.wowebook.org

Example 2.2

Flagging Uninitialized Local Variables of Primitive Data Types

Click here to view code image
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);
error!
}
}

// (1) Local variables

// (2) Always executed
// (3) Compile-time

In Example 2.2, the compiler complains that the local variable thePrice used in the
println statement at (3) may not be initialized. However, 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 compiles the body of a conditional statement only if it can deduce that the
condition is 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:
Click here to view code image
int weight = 10, thePrice = 0;
initialized

// (1’) Both local variables

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

Click here to view code image
public class VerySmartClass {
public static void main(String[] args) {
String importantMessage;
// Local reference variable
System.out.println(“The message length is: ” +
importantMessage.length());

// Compile-time error!

}
}

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, because the variable
importantMessage will not denote any object. The golden rule is to ensure that a
WOW! eBook
www.wowebook.org

reference variable, whether local or not, is assigned a reference value denoting an object
before it is used—that is, to 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:
Click here to view code image
String importantMessage = “Initialize before use!”;

Arrays and their default values are discussed in §3.4, p. 58.

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, which is also
called its scope, is discussed in more detail in §4.4, p. 114. We distinguish among the
lifetimes of variables in three contexts:
• Instance variables—members of a class, which are 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—members of a class, but which are not created for any specific
object of the class and, therefore, belong only to the class (§4.4, p. 114). They are
created when the class is loaded at runtime, and exist as long as the class is available
at runtime.
• 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.8 Which of the following 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.9 Given the following code within a method, which statement is true?
int i, j;
WOW! eBook
www.wowebook.org

j = 5;

Select the one correct answer.
(a) Local variable i is not declared.
(b) Local variable j is not declared.
(c) Local variable i is declared but not initialized.
(d) Local variable j is declared but not initialized.
(e) Local variable j is initialized but not declared.
2.10 In which of these variable declarations will the variable remain uninitialized unless
it is explicitly initialized?
Select the one correct answer.
(a) Declaration of an instance variable of type int
(b) Declaration of a static variable of type float
(c) Declaration of a local variable of type float
(d) Declaration of a static variable of type Object
(e) Declaration of an instance variable of type int[]
2.11 What will be the result of compiling and running the following program?
Click here to view code image
public class Init {
String title;
boolean published;
static int total;
static double maxPrice;
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) The program will fail to compile.
(b) The program will compile, and print |null|false|0|0.0|0.0| at
runtime.
(c) The program will compile, and print |null|true|0|0.0|100.0| at
runtime.
WOW! eBook
www.wowebook.org

(d) The program will compile, and print | |false|0|0.0|0.0| at runtime.
(e) The program will compile, and print |null|false|0|0.0|100.0| at
runtime.

Chapter Summary
The following topics were covered in this chapter:
• Basic language elements: identifiers, keywords, separators, literals, whitespace, and
comments
• Primitive data types: integral, floating-point, and boolean
• Notational representation of numbers in decimal, binary, 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.
Click here to view code image
// File: 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.0) * 5.0 / 9.0;
}
}

WOW! eBook
www.wowebook.org

3. Declarations

3.1 Class Declarations
A class declaration introduces a new reference type. For the purpose of this book, we will
use the following simplified syntax of a class declaration:
WOW! eBook
www.wowebook.org

Click here to view code image

class_modifiers class class_name
extends_clause
implements_clause // Class header
{ // Class body
field_declarations
method_declarations
constructor_declarations
}
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:
• An accessibility modifier (§4.5, p. 118)
• Additional class modifiers (§4.6, p. 120)
• Any class it extends (§7.1, p. 264)
• Any interfaces it implements (§7.6, p. 290)
The class body, enclosed in braces ({}), can contain member declarations. In this book,
we discuss the following two kinds of member declarations:
• Field declarations (§2.3, p. 40)
• Method declarations (§3.2, p. 49)
Members declared static belong to the class and are called static members. Non-static
members belong to the objects of the class and are called instance members. In addition,
the following declarations can be included in a class body:
• Constructor declarations (§3.3, p. 53)
The declarations can appear in any order in the class body. The only mandatory parts of
the class declaration syntax are the keyword class, the class name, and the class body
braces ({}), as exemplified by the following class declaration:
class X { }

To understand which 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, non-static field initializers, instance initializer blocks, and constructors. By static
code, we mean expressions and statements in a static context; by non-static code, we mean
expressions and statements in a non-static context. One crucial difference between the two
contexts is that static code can refer only to other static members.

3.2 Method Declarations
For the purpose of this book, we will use the following simplified syntax of a method
declaration:
Click here to view code image
WOW! eBook
www.wowebook.org

method_modifiers return_type method_name
(formal_parameter_list) throws_clause // Method header
{ // Method body
local_variable_declarations
statements
}
In addition to the name of the method, the method header can specify the following
information:
• Scope or accessibility modifier (§4.7, p. 123)
• Additional method modifiers (§4.8, p. 131)
• The type of the return value, or void if the method does not return any value (§6.4,
p. 224)
• A formal parameter list
• Any exceptions thrown by the method, which are specified in a throws clause
(§6.9, p. 251)
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 (§3.5, p. 72). An empty
parameter list must be specified by ( ). Each parameter is a simple variable declaration
consisting of its type and name:
Click here to view code image

optional_parameter_modifier type parameter_name
The parameter names are local to the method (§4.4, p. 117). The optional parameter
modifier final is discussed in §3.5, p. 80. It is recommended to use the @param tag in a
Javadoc comment to document the formal parameters of a method.
The signature of a method comprises the name of the method and the types of the formal
parameters only.
The method body is a block containing the local variable declarations (§2.3, p. 40) and
the statements of the method.
The mandatory parts of a method declaration are the return type, the method name, and the
method body braces ({}), as exemplified by the following method declaration:
void noAction() {}

Like member variables, member methods can be characterized as one of two types:
• Instance methods, which are discussed later in this section
• Static methods, which are discussed in §4.8, p. 132

WOW! eBook
www.wowebook.org

Statements
Statements in Java can be grouped into various categories. Variable declarations with
explicit initialization of the variables are called declaration statements (§2.3, p. 40, and
§3.4, p. 60). Other basic forms of statements are control flow statements (§6.1, p. 200) and
expression statements.
An expression statement is an expression terminated by a semicolon. Any value returned
by the expression is discarded. Only certain types of expressions have meaning as
statements:
• Assignments (§5.6, p. 158)
• Increment and decrement operators (§5.9, p. 176)
• Method calls (§3.5, p. 72)
• Object creation expressions with the new operator (§5.17, p. 195)
A solitary semicolon denotes the empty statement, which does nothing.
A block, {}, is a compound statement that can be used to group zero or more local
declarations and statements (§4.4, p. 117). 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 that 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 initializer in declaration statements (§3.4, p. 60).
Labeled statements are discussed in §6.4 on page 220.

Instance Methods and the Object Reference
Instance methods belong to every object of the class and can be invoked only 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 (§4.8, p.
133).
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.1, 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 the this reference at (2), the value of the parameter indicator
WOW! eBook
www.wowebook.org

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 with the
same name.
Example 3.1

Using the this Reference

Click here to view code image
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.printf(“Current object: %s%n”, 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);
}
}

Probable output from the program:
Current object: Light@1bc4459
Current object: Light@1bc4459
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 usage is illustrated at (4)
in Example 3.1, 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 approach is illustrated at (5) in Example 3.1, where the
current object is passed to the printf() method. The printf() method prints the
string representation of the current object (which comprises the name of the class of the
current object and the hexadecimal representation of the current object’s hash code). (The
hash code of an object is an int value that can be used to store and retrieve the object
WOW! eBook
www.wowebook.org

from special data structures called hash tables.)
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 plus 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 practice is called
method overloading. Because 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 SE platform API 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.
Click here to view code image
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:
Click here to view code image
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 a;
return 1;
return b;
return x;

}
}
}
}

// (1)
// (2)
// (3)
// (4)
// (5) Not OK.

The corresponding signatures of the five methods are as follows:
Click here to view code image
1’
2’: Number of parameters
3’: Number of parameters
4’: Order of parameters
5’: Same as 1’

methodA(int, double)
methodA(int)
methodA()
methodA(double, int)
methodA(int, double)

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, therefore, is not a valid overloading of this method.
Click here to view code image
void bake(Cake k) { /* … */ }
void bake(Pizza p) { /* … */ }
int
halfIt(int a) { return a/2; }
double halfIt(int a) { return a/2.0; }
signature.

// (1)
// (2)
// (3)
// (4) Not OK. Same

The method named bake is correctly overloaded at (1) and (2), with two different
WOW! eBook
www.wowebook.org

parameter lists. In the implementation, changing just the return type (as shown at (3) and
(4) in the preceding example), 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.
Only methods declared in the same class and those that are inherited by the class can be
overloaded. Overloaded methods should be considered to be 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 §7.10 on page 316. Method overloading should not
be confused with method overriding (§7.2, p. 268).

3.3 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.
For the purpose of this book, we will use the following simplified syntax of a constructor:
Click here to view code image

accessibility_modifier class_name (formal_parameter_list)
throws_clause // Constructor header
{ // Constructor body
local_variable_declarations
statements
}
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 §4.7, p. 123.
• 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 (§6.4, p. 224).
• 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.2, where a method declared at (2) has the same name as the
constructor declared at (1). A method must always specify a return type, whereas a
constructor does not. However, using such naming schemes is strongly discouraged.
A constructor that has no parameters, like the one at (1) in Example 3.2, is called a noargument constructor.

WOW! eBook
www.wowebook.org

Example 3.2

Namespaces

Click here to view code image
public class Name {
Name() {
// (1) No-argument constructor
System.out.println(“Constructor”);
}
void Name() {
// (2) Instance method
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
If a class does not specify any constructors, then a default constructor is generated for the
class by the compiler. The default constructor is equivalent to the following
implementation:
Click here to view code image

class_name() { super(); }
superclass constructor.

// No parameters. Calls

A default constructor is a no-argument constructor. The only action taken by the default
constructor is to call the superclass constructor. This ensures that the inherited state of the
object is initialized properly (§7.5, p. 282). 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:
Click here to view code image
class Light {
// Fields:
int
noOfWatts;
boolean indicator;
String location;
// No constructors
//…
}

// Wattage
// On or off
// Placement

class Greenhouse {
// …
Light oneLight = new Light();
}

// (1) Call to default constructor

WOW! eBook
www.wowebook.org

In this code, the following 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 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 its own constructors, rather than relying on the default
constructor. In the following example, the class Light provides a no-argument
constructor at (1).
Click here to view code image
class Light {
// …
Light() {
noOfWatts = 50;
indicator = true;
location = “X”;
}
//…
}

// (1) No-argument constructor

class Greenhouse {
// …
Light extraLight = new Light();
constructor
}

// (2) Call of explicit default

The no-argument 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 constructor, it can no longer rely on the default constructor to set the
state of its objects. If such a class requires a no-argument constructor, it must provide its
own implementation, as in the preceding example. In the next example the class Light
does not provide a no-argument constructor, but rather includes a non-zero argument
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 compiletime error, as shown at (3).
Click here to view code image
class Light {
// …
// Only non-zero argument constructor:
Light(int noOfWatts, boolean indicator, String location) {
this.noOfWatts = noOfWatts;
this.indicator = indicator;
this.location = location;
}
//…
}
class Greenhouse {
WOW! eBook
www.wowebook.org

// (1)

// …
Light moreLight = new Light(100, true, “Greenhouse”);// (2) OK
Light firstLight = new Light();
// (3) Compile-time
error
}

Overloaded Constructors
Like methods, constructors can 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 explicit implementation of the noargument constructor at (1) and that of a non-zero argument constructor at (2). The
constructors are overloaded, as is evident by their signatures. The non-zero argument
constructor at (2) is called when an object of the class Light is created at (3), and the noargument constructor is likewise called at (4). Overloading of constructors allows
appropriate initialization of objects on creation, depending on the constructor invoked (see
chaining of constructors in §7.5, p. 282). It is recommended to use the @param tag in a
Javadoc comment to document the formal parameters of a constructor.
Click here to view code image
class Light {
// …
// No-argument constructor:
Light() {
noOfWatts = 50;
indicator = true;
location = “X”;
}

// (1)

// Non-zero argument 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();
}

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)

{ /* ... */ }

WOW! eBook
www.wowebook.org

// (3) OK
// (4) OK

(d) method4()

{ /* ... */ }

(e) method5(void)

{ /* ... */ }

3.2 Which statements, when inserted at (1), will not result in compile-time errors?
Click here to view code image
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?
Click here to view code image
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 first pair of methods will not compile.
(e) The second pair of methods will not compile.
(f) The third pair of methods will not compile.
3.4 Given a class named Book, which one of these constructor declarations is valid for
the class Book?
Select the one correct answer.
WOW! eBook
www.wowebook.org

(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) A class must define a constructor.
(b) A constructor can be declared private.
(c) A constructor can return a value.
(d) A constructor must initialize all fields when a class is instantiated.
(e) A constructor can access the non-static members of a class.
3.6 What will be the result of compiling the following program?
Click here to view code image
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 compile-time error will occur at (1).
(b) A compile-time error will occur at (2).
(c) A compile-time error will occur at (3).
(d) The program will compile without errors.

3.4 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 after the array has been created.
In Java, arrays are objects. Arrays can be of primitive data types or reference types. In the
WOW! eBook
www.wowebook.org

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 public
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,
multidimensional arrays are implemented as array of arrays.
Passing array references as parameters is discussed in §3.5, p. 72. Type conversions for
array references on assignment and on method invocation are discussed in §7.7, p. 309.

Declaring Array Variables
A one-dimensional array variable declaration has either of the following syntaxes:
element_type[] array_name;
or
element_type array_name[];
where element_type can be a primitive data type or a reference type. The array variable
array_name has the type element_type[]. Note that the array size is not specified. As a
consequence, the array variable array_name can be assigned the reference value of an
array of any length, as long as its elements have element_type.
It is important to understand that the declaration does not actually create an array. Instead,
it simply declares a reference that can refer to an array object. The [] notation can also be
specified after a variable name to declare it as an array variable, but then it applies to just
that variable.
Click here to view code image
int anIntArray[], oneInteger;
Pizza[] mediumPizzas, largePizzas;

These two declarations 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 Pizza objects, but the variable
oneInteger cannot denote an array of int values—it is a simple variable of the type
int.
An array variable that is declared as a field in a class, but is not explicitly 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 (§2.4, p. 42). This behavior should not be confused with initialization of
the elements of an array during array construction.

WOW! eBook
www.wowebook.org

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:
Click here to view code image

array_name = new element_type[array_size];
The minimum value of array_size is 0; in other words zero-length arrays can be
constructed in Java. If the array size is negative, a NegativeArraySizeException
is thrown at runtime.
Given the declarations
Click here to view code image
int anIntArray[], oneInteger;
Pizza[] mediumPizzas, largePizzas;

the three arrays in the declarations can be constructed as follows:
Click here to view code image
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.
Click here to view code image

element_type1[] array_name = new element_type2[array_size];
In the preceding syntax, the array type element_type2[] must be assignable to the array
type element_type1[] (§7.7, p. 309). When the array is constructed, all of its elements are
initialized to the default value for element_type2. This is true for both member and local
arrays when they are constructed.
In the next examples, the code constructs the array, and the array elements are implicitly
initialized to their default values. For example, all elements of the array anIntArray get
the value 0, and all elements of the array mediumPizzas get the value null when the
arrays are constructed.
Click here to view code image
int[] anIntArray = new int[10];
Pizza[] mediumPizzas = new Pizza[5];
null

// Default element value: 0
// Default element value:

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
WOW! eBook
www.wowebook.org

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:
Click here to view code image

element_type[] array_name = { array_initialize_list };
This form of initialization applies to fields as well as to local arrays. The
array_initialize_list is a comma-separated list of zero or more expressions. Such an array
initializer results in the construction and initialization of the array.
Click here to view code image
int[] anIntArray = {13, 49, 267, 15, 215};

In this declaration statement, the variable anIntArray is declared as a reference to an
array of ints. The array initializer results in the construction of an array to hold five
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.
Click here to view code image
Pizza[] pizzaOrder = { new Pizza(), new Pizza(), null };

In this declaration statement, the variable pizzaOrder is declared as a reference to an
array of Pizza objects. The array initializer constructs an array 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. The reference value of
the array of Pizza objects is assigned to the reference pizzaOrder. Note also that this
declaration statement actually creates three objects: the array object with three references
and the two Pizza objects.
The expressions in the array_initialize_list are evaluated from left to right, and the array
name obviously cannot occur in any of the expressions in the list. In the preceding
examples, the array_initialize_list is terminated by the right brace, }, of the block. The list
can also be legally terminated by a comma. The following array has length 2, and not 3:
Click here to view code image
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.
Click here to view code image
// 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”

WOW! eBook
www.wowebook.org

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:
array_name [index_expression]
Each individual element is treated as a simple variable of the element type. The index is
specified by the index_expression, whose value should be promotable to an int value;
otherwise, a compile-time error is flagged. Since the lower bound of an array index is
always 0, the upper bound is 1 less than the array size—that is, array_name.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
is less than 0, or greater than or equal to array_name.length, an
ArrayIndexOutOfBoundsException is thrown. A program can either check the
index explicitly or catch the runtime exception (§6.5, p. 230), but an illegal index is
typically an indication of a programming error.
In the array element access expression, the array_name can be any expression that returns
a reference to an array. For example, the expression on the right-hand side of the following
assignment statement returns the character 'H' at index 1 in the character array returned
by a call to the toCharArray() method of the String class:
Click here to view code image
char letter = “AHA”.toCharArray()[1];

// ‘H’

The array operator [] is used to declare array types (Topping[]), specify the array size
(new Topping[3]), and access array elements (toppings[1]). This operator is not
used when the array reference is manipulated, such as in an array reference assignment
(§7.9, p. 312), or when the array reference is passed as an actual parameter in a method
call (§3.5, p. 77).
Example 3.3 shows traversal of arrays using for loops (§6.3, p. 215 and p. 217). A
for(;;) loop at (3) in the main() method 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). Both of these methods also use a for(;;) loop. The
loop variable is initialized to a start value—0 in (3) and (5), and 1 in (6). The loop
condition tests whether the loop variable is less than the length of the array; this
guarantees that the loop will terminate when the last element has been accessed. The loop
variable is incremented after each iteration to access the next element.
A for(:) loop at (4) in the main() method is used to print the minimum values from
the trials, as elements are read consecutively from the array, without keeping track of an
index value.

WOW! eBook
www.wowebook.org

Example 3.3

Using Arrays

Click here to view code image
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) {
// Initialize the array.
randomize(trialArray);

// (1)
// (2)
// (3)

// Find and store the minimum value.
storeMinimum[i] = findMinimum(trialArray);
}
// Print the minimum values:
for (double minValue : storeMinimum)
System.out.printf(“%.4f%n”, minValue);

(4)

}
public static void randomize(double[] valArray) {
for (int i = 0; i < valArray.length; ++i)
valArray[i] = Math.random() * 100.0;
}

// (5)

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)

}

Probable 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 can be used to
construct arrays using an array creation expression:
Click here to view code image

element_type1[] array_name = new element_type2[array_size];

// (1)

int[] intArray = new int[5];
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. By comparison, the following
declaration statement both creates the array and initializes the array elements to specific
values given in the array initializer:
WOW! eBook
www.wowebook.org

Click here to view code image

element_type[] array_name = { array_initialize_list };

// (2)

int[] intArray = {3, 5, 2, 8, 6};
However, the array initializer is not an expression. Java has another array creation
expression, called an anonymous array, which allows the concept of the array creation
expression from (1) to be combined with the array initializer from (2), so as to create and
initialize an array object:
Click here to view code image

new element_type[] { array_initialize_list }
new int[] {3, 5, 2, 8, 6}
This 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 declaration statements are
equivalent:
Click here to view code image
int[] intArray = {3, 5, 2, 8, 6};
int[] intArray = new int[] {3, 5, 2, 8, 6};

// (1)
// (2)

In (1), an array initializer is used to create and initialize the elements. In (2), an
anonymous array expression is used. It is tempting to use the array initializer as an
expression—for example, in an assignment statement, as a shortcut for assigning values to
array elements in one go. However, this is illegal; instead, an anonymous array expression
should be used. The concept of the anonymous array combines the definition and the
creation of the array into one operation.
Click here to view code image
int[] daysInMonth;
daysInMonth = {31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31};
// Compile-time
error
daysInMonth = new int[] {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; //
OK

In Example 3.4, an anonymous array is constructed at (1), and passed as an actual
parameter to the static method findMinimum() defined at (2). Note that no array name
or array size is specified for the anonymous array.

WOW! eBook
www.wowebook.org

Example 3.4

Using Anonymous Arrays

Click here to view code image
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 refer to other arrays. In Java, an array of arrays can be defined as follows:
Click here to view code image

element_type[][]...[] array_name;
or
Click here to view code image

element_type array_name[][]...[];
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 often called multidimensional arrays.
The following declarations are all equivalent:
Click here to view code image
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.
Click here to view code image
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 five 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.
WOW! eBook
www.wowebook.org

However, such an interpretation is not dictated by the Java language.
Each row in the previous matrix is denoted by mXnArray[i], where 0 ≤ i < 4. Each
element in the ith row, mXnArray[i], is accessed by mXnArray[i][j], where 0 ≤
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 ≤ i < 4.
Multidimensional arrays can also be constructed and explicitly initialized using the array
initializers discussed for simple arrays. Note that each row is an array that uses an array
initializer to specify its values:
Click here to view code image
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; when they do not, they
are called ragged arrays. The array of arrays pizzaGalore in the following code has
five rows; the first four rows have different lengths but the fifth row is left unconstructed:
Click here to view code image
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 such a case, these arrays are left unconstructed.
For example, an array of arrays to represent a room on a floor in a 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 successively.
Click here to view code image
HotelRoom[][][][] rooms = new HotelRoom[10][5][][];
hotels.

// Just streets and

The preceding 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:
Click here to view code image
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
WOW! eBook
www.wowebook.org

floor.

The next code snippet 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.1, the array of
arrays matrix is depicted after the elements have been explicitly initialized.
Click here to view code image
double[][] matrix = new double[3][];

// Number of rows.

for (int i = 0; i < matrix.length; ++i)
matrix[i] = new double[i + 1];

// Construct a row.

Figure 3.1

Array of Arrays

Two other ways of initializing such an array of arrays are shown next. The first approach
uses array initializers, and the second uses an anonymous array of arrays.
Click here to view code image
double[][] matrix2 = {
{0.0},
{0.0, 0.0},
{0.0, 0.0, 0.0}
};

//
//
//
//

Using array initializers.
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[][], a two-dimensional array of double
values. The type of the variable matrix[i] (where 0 ≤ i< matrix.length) is
double[], a one-dimensional array of double values. The type of the variable
matrix[i][j] (where 0 ≤ i< matrix.length and 0 ≤ j< matrix[i].length)
is double, a simple variable of type double.
WOW! eBook
www.wowebook.org

Nested loops are a natural match for manipulating multidimensional arrays. In Example
3.5, a rectangular 4 × 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 ≤ i< mXnArray.length), and the inner loop at (3)
traverses the elements in each row in turn (mXnArray[i][j], where 0 ≤ j<
mXnArray[i].length). The outer loop is executed mXnArray.length times, or 4
times, and the inner loop is executed (mXnArray.length) ×
(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. Several
examples of its use are provided in §6.3, p. 217.
Example 3.5

Using Multidimensional Arrays

Click here to view code image
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
// Find the minimum value in a M X N matrix:
int min = mXnArray[0][0];
for (int i = 0; i < mXnArray.length; ++i)
// Find min in mXnArray[i], in the row given by index i:
for (int j = 0; j < mXnArray[i].length; ++j)
min = Math.min(min, mXnArray[i][j]);

// (1)

// (2)
// (3)

System.out.println(“Minimum value: ” + min);
}
}

Output from the program:
Minimum value: 5

Sorting Arrays
Sorting implies ordering the elements according to some ranking criteria, usually based on
the values of the elements. The values of numeric data types can be compared and ranked
by using the relational operators. For comparing objects of a class, the class typically
implements the compareTo() method of the Comparable interface. The ordering
defined by this method is called the natural ordering for the objects of the class. The
wrapper classes for primitive values and the String class implement the
compareTo() method (§8.3, p. 350, and §8.4, p. 363, respectively).
The java.util.Arrays class provides many overloaded versions of the sort()
method to sort practically any type of array.
WOW! eBook
www.wowebook.org

void sort(type[] array)

Permitted type for elements includes byte, char, double, float, int, long,
short, and Object. The method sorts the elements in the array according to their
natural ordering. In the case of an array of objects being passed as argument, the
objects must be mutually comparable; that is, it should be possible to compare any
two objects in the array according to the natural ordering defined by the
compareTo() method of the Comparable interface.
An appropriate import statement should be included in the source code to access the
java.util.Arrays class. In the next code snippet, an array of strings is sorted
according to natural ordering for strings—that is, based on the Unicode values of the
characters in the strings:
Click here to view code image
String[] strArray = {“biggest”, “big”, “bigger”, “Bigfoot”};
Arrays.sort(strArray);
// Natural ordering: [Bigfoot, big, bigger,
biggest]

The next examples illustrate sorting an array of primitive values (int) at (1), and an array
of type Object containing mutually comparable elements (String) at (2). In (3), the
numerical values are autoboxed into their corresponding wrapper classes (§8.3, p. 346),
but the objects of different wrapper classes and the String class are not mutually
comparable. In (4), the numerical values are also autoboxed into their corresponding
wrapper classes, but again the objects of different wrapper classes are not mutually
comparable. A ClassCastException is thrown when the elements are not mutually
comparable.
Click here to view code image
int[] intArray = {5, 3, 7, 1};
Arrays.sort(intArray);
5, 7]

// int
// (1) Natural ordering: [1, 3,

Object[] objArray1 = {“I”, “am”, “OK”};
Arrays.sort(objArray1);
am]

// String
// (2) Natural ordering: [I, OK,

Object[] objArray2 = {23, “ten”, 3.14};
Arrays.sort(objArray2);

// Not mutually comparable
// (3) ClassCastException

Number[] numbers = {23, 3.14, 10L};
Arrays.sort(numbers);

// Not mutually comparable
// (4) ClassCastException

Searching Arrays
A common operation on an array is to search the array for a given element, called the key.
The java.util.Arrays class provides overloaded versions of the
binarySearch() method to search in practically any type of array that is sorted.

WOW! eBook
www.wowebook.org

Click here to view code image
int binarySearch(type[] array, type key)

Permitted type for elements include byte, char, double, float, int, long,
short, and Object. The array must be sorted in ascending order before calling
this method, or the results are unpredictable. In the case where an array of objects is
passed as argument, the objects must be sorted in ascending order according to their
natural ordering, as defined by the Comparable interface.
The method returns the index to the key in the sorted array, if the key exists. The
index is then guaranteed to be greater or equal to 0. If the key is not found, a
negative index is returned, corresponding to –(insertion point + 1), where insertion
point is the index of the element where the key would have been found, if it had
been in the array. If there are duplicate elements equal to the key, there is no
guarantee which duplicate’s index will be returned. The elements and the key must
be mutually comparable.
An appropriate import statement should be included in the source code to access the
java.util.Arrays class. In the code that follows, the return value –3 indicates that
the key would have been found at index 2 had it been in the list:
Click here to view code image
// Sorted String array (natural ordering):
// Search in natural ordering:
int index1 = Arrays.binarySearch(strArray,
int index2 = Arrays.binarySearch(strArray,
int index3 = Arrays.binarySearch(strArray,

[Bigfoot, big, bigger, biggest]
“bigger”);
// Successful:
2
“bigfeet”); // Unsuccessful: -3
“bigmouth”); // Unsuccessful: -5

Results are unpredictable if the array is not sorted, or if the ordering used in the search is
not the same as the sort ordering. Searching in the strArray using natural ordering
when the array is sorted in reverse natural ordering gives the wrong result:
Click here to view code image
// Sorted String array (inverse natural ordering): [biggest, bigger, big,
Bigfoot]
// Search in natural ordering:
int index4 = Arrays.binarySearch(strArray, “big”); // -1 (INCORRECT)

A ClassCastException is thrown if the key and the elements are not mutually
comparable:
Click here to view code image
int index5 = Arrays.binarySearch(strArray, 4); // Key: 4 =>
ClassCastException

However, this incompatibility is caught at compile time in the case of arrays with
primitive values:
Click here to view code image
// Sorted int array (natural ordering): [1, 3, 5, 7]
int index6 = Arrays.binarySearch(intArray, 4.5);//Key: 4.5 => compile-time
error!

The method binarySearch() derives its name from the divide-and-conquer algorithm
WOW! eBook
www.wowebook.org

that it uses to perform the search. It repeatedly divides the remaining elements to be
searched into two halves and selects the half containing the key to continue the search in,
until either the key is found or there are no more elements left to search.

Review Questions
3.7 Given the following declaration, which expression returns the size of the array,
assuming that the array reference has been properly 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()
(g) array[].size
(h) array.size
3.8 Is it possible to create arrays of length zero?
Select the one correct answer.
(a) Yes, you can create arrays of any type with length zero.
(b) Yes, but only for primitive data types.
(c) Yes, but only for arrays of reference types.
(d) 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.9 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];
WOW! eBook
www.wowebook.org

3.10 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 ] };
(e) int i[4] = { 1, 2, 3, 4 };
3.11 What would be the result of compiling and running the following program?
Click here to view code image
public 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.12 What would be the result of compiling and running the following program?
Click here to view code image
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);
WOW! eBook
www.wowebook.org

}
}

Select the one correct answer.
(a) The program will fail to compile because of uninitialized variables.
(b) The program will throw a java.lang.NullPointerException when
run.
(c) The program will print 0 false NaN null.
(d) The program will print 0 false 0 null.
(e) The program will print null 0 0 null.
(f) The program will print null false 0 null.

3.5 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).
Declaring methods is discussed in §3.2, p. 49. Invoking static methods on classes is
discussed in §4.8, p. 132.
The syntax of a method call can be any one of the following:
Click here to view code image

object_reference.method_name(actual_parameter_list)
class_name.static_method_name(actual_parameter_list)
method_name(actual_parameter_list)
The object_reference must be an expression that evaluates to a reference value denoting
the object on which the method is called. If the caller and the callee are the same, object
reference can be omitted (see the discussion of the this reference in §3.2, p. 50). The
class_name can be the fully qualified name (§4.2, p. 97) of the class. The
actual_parameter_list is comma separated if there is more than one parameter. The
parentheses are mandatory even if the actual parameter list is empty. This distinguishes the
method call from field access. One can specify fully qualified names for classes and
packages using the dot operator (.).
Click here to view code image
objRef.doIt(time, place);
int i = java.lang.Math.abs(-1);
int j = Math.abs(-1);
someMethod(ofValue);
someObjRef.make().make().make();

//
//
//
//
//

Explicit object reference
Fully qualified class name
Simple class name
Object or class implicitly implied
make() returns a reference value

The dot operator (.) has left associativity. In the last code line, the first call of the
make() method returns a reference value that denotes the object on which to execute the
WOW! eBook
www.wowebook.org

next call, and so on. This is an example of call chaining.
Each actual parameter (also called an argument) is an expression that is evaluated, and
whose value is passed to the method when the method is invoked. Its value can vary from
invocation to invocation. Formal parameters are parameters defined in the method
declaration (§3.2, p. 49) and are local to the method (§2.4, p. 44).
In Java, all parameters are passed by value—that is, an actual parameter is evaluated and
its value is assigned to the corresponding formal parameter. Table 3.1 summarizes the
value that is passed depending on the type of the parameters. In the case of primitive data
types, the data value of the actual parameter is passed. If the actual parameter is a
reference to an object, the reference value of the denoted object is passed and not the
object itself. Analogously, if the actual parameter is an array element of a primitive data
type, its data value is passed, and if the array element is a reference to an object, then its
reference value is passed.

Table 3.1

Parameter Passing by Value

It should also be stressed that each invocation of a method has its own copies of the formal
parameters, as is the case for any local variables in the method (§6.5, p. 230).
The order of evaluation in the actual parameter list is always from left to right. The
evaluation of an actual parameter can be influenced by an earlier evaluation of an actual
parameter. Given the following declaration:
int i = 4;

the method call
leftRight(i++, i);

is effectively the same as
leftRight(4, 5);

and not the same as
leftRight(4, 4);

An overview of the conversions that can take place in a method invocation context is
provided in §5.2, p. 148. Method invocation conversions for primitive values are
discussed in the next subsection (p. 73), and those for reference types are discussed in
§7.10, p. 315. Calling variable arity methods is discussed in §3.6, p. 81.
For the sake of simplicity, the examples in subsequent sections primarily show method
invocation on the same object or the same class. The parameter passing mechanism is no
different when different objects or classes are involved.

WOW! eBook
www.wowebook.org

Passing Primitive Data Values
An actual parameter is an expression that is evaluated first, with the resulting value then
being assigned to the corresponding formal parameter at method invocation. The use of
this value in the method has no influence on the actual parameter. In particular, when the
actual parameter is a variable of a primitive data type, the value of the variable is copied to
the formal parameter at method invocation. Since formal parameters are local to the
method, any changes made to the formal parameter will not be reflected in the actual
parameter after the call completes.
Legal type conversions between actual parameters and formal parameters of primitive data
types are summarized here from Table 5.1, p. 147:
• Widening primitive conversion
• Unboxing conversion, followed by an optional widening primitive conversion
These conversions are illustrated by invoking the following method
Click here to view code image
static void doIt(long i) { /* … */ }

with the following code:
Click here to view code image
Integer intRef = 34;
Long longRef = 34L;
doIt(34);
// (1) Primitive widening conversion: long <— int
doIt(longRef);
// (2) Unboxing: long <— Long
doIt(intRef);
// (3) Unboxing, followed by primitive widening conversion:
//
long <— int <— Integer

However, for parameter passing, there are no implicit narrowing conversions for integer
constant expressions (§5.2, p. 148).

WOW! eBook
www.wowebook.org

Example 3.6

Passing Primitive Values

Click here to view code image
public class CustomerOne {
public static void main (String[] args) {
PizzaFactory pizzaHouse = new PizzaFactory();
int pricePrPizza = 15;
System.out.println(“Value of pricePrPizza before call: ” + pricePrPizza);
double totPrice = pizzaHouse.calcPrice(4, pricePrPizza);
//
(1)
System.out.println(“Value of pricePrPizza after call: ” + pricePrPizza);
}
}
class PizzaFactory {
public double calcPrice(int numberOfPizzas, double pizzaPrice) {
//
(2)
pizzaPrice = pizzaPrice / 2.0;
// Changes price.
System.out.println(“Changed pizza price in the method: ” + pizzaPrice);
return numberOfPizzas * pizzaPrice;
}
}

Output from the program:
Click here to view code image
Value of pricePrPizza before call: 15
Changed pizza price in the method: 7.5
Value of pricePrPizza after call: 15

In Example 3.6, the method calcPrice() is defined in the class PizzaFactory at
(2). It is called from the CustomerOne.main() method at (1). The value of the first
actual parameter, 4, is copied to the int formal parameter numberOfPizzas. Note that
the second actual parameter pricePrPizza is of the type int, while the corresponding
formal parameter pizzaPrice is of the type double. Before the value of the actual
parameter pricePrPizza is copied to the formal parameter pizzaPrice, it is
implicitly widened to a double. The passing of primitive values is illustrated in Figure
3.2.

Figure 3.2

Parameter Passing: Primitive Data Values

The value of the formal parameter pizzaPrice is changed in the calcPrice()
method, but this does not affect the value of the actual parameter pricePrPizza on
WOW! eBook
www.wowebook.org

return: It still has the value 15. The bottom line is that the formal parameter is a local
variable, and changing its value does not affect the value of the actual parameter.

Passing Reference Values
If the actual parameter expression evaluates to a reference value, the resulting reference
value is assigned to the corresponding formal parameter reference at method invocation.
In particular, if an actual parameter is a reference to an object, the reference value stored
in the actual parameter is passed. Consequently, both the actual parameter and the formal
parameter are aliases to the object denoted by this reference value during the invocation of
the method. In particular, this implies that changes made to the object via the formal
parameter will be apparent after the call returns.
Type conversions between actual and formal parameters of reference types are discussed
in §7.10, p. 315.
In Example 3.7, a Pizza object is created at (1). Any object of the class Pizza created
using the class declaration at (5) always results in a beef pizza. In the call to the bake()
method at (2), the reference value of the object referenced by the actual parameter
favoritePizza is assigned to the formal parameter pizzaToBeBaked in the
declaration of the bake() method at (3).
Example 3.7

Passing Reference Values

Click here to view code image
public class CustomerTwo {
public static void main (String[] args) {
Pizza favoritePizza = new Pizza();
// (1)
System.out.println(“Meat on pizza before baking: ” + favoritePizza.meat);
bake(favoritePizza);
// (2)
System.out.println(“Meat on pizza after baking: ” + favoritePizza.meat);
}
public static void bake(Pizza pizzaToBeBaked) {
// (3)
pizzaToBeBaked.meat = “chicken”; // Change the meat on the pizza.
pizzaToBeBaked = null;
// (4)
}
}
class Pizza {
String meat = “beef”;
}

// (5)

Output from the program:
Click here to view code image
Meat on pizza before baking: beef
Meat on pizza after baking: chicken

One particular consequence of passing reference values to formal parameters is that any
changes made to the object via formal parameters will be reflected back in the calling
method when the call returns. In this case, the reference favoritePizza will show that
chicken has been substituted for beef on the pizza. Setting the formal parameter
WOW! eBook
www.wowebook.org

pizzaToBeBaked to null at (4) does not change the reference value in the actual
parameter favoritePizza. The situation at method invocation, and just before the
return from method bake(), is illustrated in Figure 3.3.

Figure 3.3

Parameter Passing: Reference Values

In summary, the formal parameter can only change the state of the object whose reference
value was passed to the method.
The parameter passing strategy in Java is call by value and not call by reference,
regardless of the type of the parameter. Call by reference would have allowed values in the
actual parameters to be changed via formal parameters; that is, the value in
pricePrPizza would be halved in Example 3.6 and favoritePizza would be set
to null in Example 3.7. However, this cannot be directly implemented in Java.

WOW! eBook
www.wowebook.org

Passing Arrays
The discussion of passing reference values in the previous section is equally valid for
arrays, as arrays are objects in Java. Method invocation conversions for array types are
discussed along with those for other reference types in §7.10, p. 315.
In Example 3.8, the idea is to repeatedly swap neighboring elements in an integer array
until the largest element in the array percolates to the last position in the array.
Example 3.8

Passing Arrays

Click here to view code image
public class Percolate {
public static void main (String[] args) {
int[] dataSeq = {8,4,6,2,1};
// Create and initialize an array.
// Write array before percolation:
printIntArray(dataSeq);
// Percolate:
for (int index = 1; index < dataSeq.length; ++index)
if (dataSeq[index-1] > dataSeq[index])
swap(dataSeq, index-1, index);

// (1)

// Write array after percolation:
printIntArray(dataSeq);
}
public static void swap(int[] intArray, int i, int j) { // (2)
int tmp = intArray[i]; intArray[i] = intArray[j]; intArray[j] = tmp;
}
public static void swap(int v1, int v2) {
error!
int tmp = v1; v1 = v2; v2 = tmp;
}
public static void printIntArray(int[] array) {
for (int value : array)
System.out.print(” ” + value);
System.out.println();
}

// (3) Logical

// (4)

}

Output from the program:
8 4 6 2 1
4 6 2 1 8

Note that in the declaration of the method swap() at (2), the formal parameter
intArray is of the array type int[]. The swap() method is called in the main()
method at (1), where one of the actual parameters is the array variable dataSeq. The
reference value of the array variable dataSeq is assigned to the array variable
intArray at method invocation. After return from the call to the swap() method, the
array variable dataSeq will reflect the changes made to the array via the corresponding
formal parameter. This situation is depicted in Figure 3.4 at the first call and return from
WOW! eBook
www.wowebook.org

the swap() method, indicating how the values of the elements at indices 0 and 1 in the
array have been swapped.

Figure 3.4

Parameter Passing: Arrays

However, the declaration of the swap() method at (3) will not swap two values. The
method call
Click here to view code image
swap(dataSeq[index-1], dataSeq[index]);

will have no effect on the array elements, as the swapping is done on the values of the
formal parameters.
The method printIntArray() at (4) also has a formal parameter of array type
int[]. Note that the formal parameter is specified as an array reference using the []
notation, but this notation is not used when an array is passed as an actual parameter.

Array Elements as Actual Parameters
Array elements, like other variables, can store values of primitive data types or reference
values of objects. In the latter case, they can also be arrays—that is, arrays of arrays (§3.4,
p. 63). If an array element is of a primitive data type, its data value is passed; if it is a
reference to an object, the reference value is passed. The method invocation conversions
apply to the values of array elements as well.

WOW! eBook
www.wowebook.org

Example 3.9

Array Elements as Primitive Data Values

Click here to view code image
public class FindMinimum {
public static void main(String[] args) {
int[] dataSeq = {6,4,8,2,1};
int minValue = dataSeq[0];
for (int index = 1; index < dataSeq.length; ++index)
minValue = minimum(minValue, dataSeq[index]);

// (1)

System.out.println(“Minimum value: ” + minValue);
}
public static int minimum(int i, int j) {
return (i <= j) ? i : j;
}

// (2)

}

Output from the program:
Minimum value: 1

In Example 3.9, the value of all but one element of the array dataSeq is retrieved and
passed consecutively at (1) to the formal parameter j of the minimum() method defined
at (2). The discussion in §3.5, p. 73, on passing primitive values also applies to array
elements that have primitive values.
In Example 3.10, the formal parameter seq of the findMinimum() method defined at
(4) is an array variable. The variable matrix denotes an array of arrays declared at (1)
simulating a multidimensional array, which has three rows, where each row is a simple
array. The first row, denoted by matrix[0], is passed to the findMinimum() method
in the call at (2). Each remaining row is passed by its reference value in the call to the
findMinimum() method at (3).

WOW! eBook
www.wowebook.org

Example 3.10

Array Elements as Reference Values

Click here to view code image
public class FindMinimumMxN {
public static void main(String[] args) {
int[][] matrix = { {8,4},{6,3,2},{7} };
int min = findMinimum(matrix[0]);
for (int i = 1; i < matrix.length; ++i) {
int minInRow = findMinimum(matrix[i]);
min = Math.min(min, minInRow);
}
System.out.println(“Minimum value in matrix: ” + min);

// (1)
// (2)
// (3)

}
public static int findMinimum(int[] seq) {
int min = seq[0];
for (int i = 1; i < seq.length; ++i)
min = Math.min(min, seq[i]);
return min;
}

// (4)

}

Output from the program:
Minimum value in matrix: 2

Parameters
A formal parameter can be declared with the keyword final preceding the parameter
declaration in the method declaration. A final parameter is also known as a blank final
variable; that is, it is blank (uninitialized) until a value is assigned to it, (e.g., at method
invocation) and then the value in the variable cannot be changed during the lifetime of the
variable (see also the discussion in §4.8, p. 133). The compiler can treat final variables
as constants for code optimization purposes. Declaring parameters as final prevents
their values from being changed inadvertently. A formal parameter’s declaration as
final does not affect the caller’s code.
The declaration of the method calcPrice() from Example 3.6 is shown next, with the
formal parameter pizzaPrice declared as final:
Click here to view code image
public double calcPrice(int numberOfPizzas, final double pizzaPrice) { //
(2’)
pizzaPrice = pizzaPrice/2.0;
// (3) Not allowed
return numberOfPizzas * pizzaPrice;
}

If this declaration of the calcPrice() method is compiled, the compiler will not allow
the value of the final parameter pizzaPrice to be changed at (3) in the body of the
method.
As another example, the declaration of the method bake() from Example 3.7 is shown
here, with the formal parameter pizzaToBeBaked declared as final:
WOW! eBook
www.wowebook.org

Click here to view code image
public static void bake(final Pizza pizzaToBeBaked) { // (3)
pizzaToBeBaked.meat = “chicken”;
// (3a) Allowed
pizzaToBeBaked = null;
// (4) Not allowed
}

If this declaration of the bake() method is compiled, the compiler will not allow the
reference value of the final parameter pizzaToBeBaked to be changed at (4) in the
body of the method. Note that this applies to the reference value in the final parameter,
but not to the object denoted by this parameter. The state of the object can be changed as
before, as shown at (3a).

3.6 Variable Arity Methods
A fixed arity method must be called with the same number of actual parameters (also
called arguments) as the number of formal parameters specified in its declaration. If the
method declaration specifies two formal parameters, every call of this method must
specify exactly two arguments. We say that the arity of this method is 2. In other words,
the arity of such a method is fixed, and it is equal to the number of formal parameters
specified in the method declaration.
Java also allows declaration of variable arity methods, meaning that the number of
arguments in its call can be varied. As we shall see, invocations of such a method may
contain more actual parameters than formal parameters. Variable arity methods are heavily
employed in formatting text representation of values, as demonstrated by the variable arity
method System.out.printf() that is used in many examples for this purpose.
The last formal parameter in a variable arity method declaration is declared as follows:
type... formal_parameter_name
The ellipsis (...) is specified between the type and the formal_parameter_name. The
type can be a primitive type, a reference type, or a type parameter. Whitespace can be
specified on both sides of the ellipsis. Such a parameter is usually called a variable arity
parameter (also known as varargs).
Apart from the variable arity parameter, a variable arity method is identical to a fixed arity
method. The method publish() is a variable arity method:
Click here to view code image
public static void publish(int n, String… data) {
// (int, String[])
System.out.println(“n: ” + n + “, data size: ” + data.length);
}

The variable arity parameter in a variable arity method is always interpreted as having an
array type:
type[]
In the body of the publish() method, the variable arity parameter data has the type
String[], so it is a simple array of Strings.
Only one variable arity parameter is permitted in the formal parameter list, and it is always
the last parameter in the formal parameter list. Given that the method declaration has n
WOW! eBook
www.wowebook.org

formal parameters, and the method call has k actual parameters, k must be equal to or
greater than n – 1. The last k – n + 1 actual parameters are evaluated and stored in an array
whose reference value is passed as the value of the actual parameter. In the case of the
publish() method, n is equal to 2, so k can be 1, 2, 3, and so on. The following
invocations of the publish() method show which arguments are passed in each method
call:
Click here to view code image
publish(1);
publish(2, “two”);
publish(3, “two”, “three”);

// (1, new String[] {})
// (2, new String[] {“two”})
// (3, new String[] {“two”, “three”})

Each method call results in an implicit array being created and passed as an argument.
This array can contain zero or more argument values that do not correspond to the formal
parameters preceding the variable arity parameter. This array is referenced by the variable
arity parameter data in the method declaration. The preceding calls would result in the
publish() method printing the following output:
n: 1, data size: 0
n: 2, data size: 1
n: 3, data size: 2

To overload a variable arity method, it is not enough to change the type of the variable
arity parameter to an explicit array type. The compiler will complain if an attempt is made
to overload the method transmit(), as shown in the following code:
Click here to view code image
public static void transmit(String… data) { } // Compile-time error!
public static void transmit(String[] data) { } // Compile-time error!

These declarations would result in two methods with equivalent signatures in the same
class, which is not permitted.
Overloading and overriding of methods with variable arity are discussed in §7.10, p. 316.

Calling a Variable Arity Method
Example 3.11 illustrates various aspects of calling a variable arity method. The method
flexiPrint() in the VarargsDemo class has a variable arity parameter:
Click here to view code image
public static void flexiPrint(Object… data) { // Object[]
//…
}

The variable arity method prints the name of the Class object representing the actual
array that is passed at runtime. It prints the number of elements in this array as well as the
text representation of each element in the array.
The method flexiPrint() is called in the main() method. First with the values of
primitive types and Strings ((1) to (8)), then it is called with the program arguments (p.
85) supplied in the command line, ((9) to (11)).
Compiling the program results in a warning at (9), which we ignore for the time being.
The program can still be run, as shown in Example 3.11. The numbers at the end of the
WOW! eBook
www.wowebook.org

lines in the output relate to numbers in the code, and are not printed by the program.
Example 3.11

Calling a Variable Arity Method

Click here to view code image
public class VarargsDemo {
public static void flexiPrint(Object… data) { // Object[]
// Print the name of the Class object for the varargs parameter.
System.out.print(“Type: ” + data.getClass().getName());
System.out.println(“

No. of elements: ” + data.length);

System.out.print(“Element values: “);
for(Object element : data)
System.out.print(element + ” “);
System.out.println();
}
public static void
int
day
String monthName
int
year

main(String… args) {
= 13;
= “August”;
= 2009;

// Passing primitives and non-array types:
flexiPrint();
// (1) new
flexiPrint(day);
// (2) new
{Integer.valueOf(day)}
flexiPrint(day, monthName);
// (3) new
{Integer.valueOf(day),
//
flexiPrint(day, monthName, year); // (4) new
{Integer.valueOf(day),
//
//
System.out.println();
// Passing an array type:
Object[] dateInfo = {day,
//
{Integer.valueOf(day),
monthName,
//
year};
//
flexiPrint(dateInfo);
//
flexiPrint((Object) dateInfo);
//
dateInfo}
flexiPrint(new Object[]{dateInfo});//
System.out.println();
// Explicit varargs or non-varargs
flexiPrint(args);
flexiPrint((Object) args);
flexiPrint((Object[]) args);

Object[] {}
Object[]
Object[]
monthName}
Object[]
monthName,
Integer.valueOf(year)}

(5) new Object[]
monthName,
Integer.valueOf(year)}
(6) Non-varargs call
(7) new Object[] {(Object)
(8) Non-varargs call

call:
// (9) Warning!
// (10) Explicit varargs call
// (11) Explicit non-varargs call

}
}

Compiling the program:
Click here to view code image
>javac VarargsDemo.java
VarargsDemo.java:41: warning: non-varargs call of varargs method with inexact
argument type for last parameter;
flexiPrint(args);
// (9) Warning!
WOW! eBook
www.wowebook.org

^
cast to Object for a varargs call
cast to Object[] for a non-varargs call and to suppress this warning
1 warning

Running the program:
Click here to view code image
>java VarargsDemo To arg or not to arg
Type: [Ljava.lang.Object; No. of elements:
Element values:
Type: [Ljava.lang.Object; No. of elements:
Element values: 13
Type: [Ljava.lang.Object; No. of elements:
Element values: 13 August
Type: [Ljava.lang.Object; No. of elements:
Element values: 13 August 2009

0

(1)

1

(2)

2

(3)

3

(4)

Type: [Ljava.lang.Object; No. of elements: 3
Element values: 13 August 2009
Type: [Ljava.lang.Object; No. of elements: 1
Element values: [Ljava.lang.Object;@1eed786
Type: [Ljava.lang.Object; No. of elements: 1
Element values: [Ljava.lang.Object;@1eed786

(6)

Type: [Ljava.lang.String; No. of elements: 6
Element values: To arg or not to arg
Type: [Ljava.lang.Object; No. of elements: 1
Element values: [Ljava.lang.String;@187aeca
Type: [Ljava.lang.String; No. of elements: 6
Element values: To arg or not to arg

(9)

(7)
(8)

(10)
(11)

Variable Arity and Fixed Arity Method Calls
The calls in (1) to (4) in Example 3.11 are all variable arity calls, as an implicit Object
array is created, in which the values of the actual parameters are stored. The reference
value of this array is passed to the method. The printout shows that the type of the
parameter is actually an array of Objects ([Ljava.lang.Object;).
The call at (6) differs from the previous calls, in that the actual parameter is an array that
has the same type (Object[]) as the variable arity parameter, without having to create
an implicit array. In such a case, no implicit array is created, and the reference value of the
array dateInfo is passed to the method. See also the result from this call at (6) in the
output. The call at (6) is a fixed arity call (also called a non-varargs call), where no
implicit array is created:
Click here to view code image
flexiPrint(dateInfo);

// (6) Non-varargs call

However, if the actual parameter is cast to the type Object as in (7), a variable arity call
is executed:
Click here to view code image
flexiPrint((Object) dateInfo);

// (7) new Object[] {(Object) dateInfo}

The type of the actual argument is now not the same as that of the variable arity parameter,
WOW! eBook
www.wowebook.org

resulting in an array of the type Object[] being created, in which the array dateInfo
is stored as an element. The printout at (7) shows that only the text representation of the
dateInfo array is printed, and not its elements, as it is the sole element of the implicit
array.
The call at (8) is a fixed arity call, for the same reason as the call in (6). Now, however, the
array dateInfo is explicitly stored as an element in an array of the type Object[] that
matches the type of the variable arity parameter:
Click here to view code image
flexiPrint(new Object[]{dateInfo});// (8) Non-varargs call

The output from (8) is the same as the output from (7), where the array dateInfo was
passed as an element in an implicitly created array of type Object[].
The compiler issues a warning for the call at (9):
Click here to view code image
flexiPrint(args);

// (9) Warning!

The actual parameter args is an array of the type String[], which is a subtype of
Object[]—the type of the variable arity parameter. The array args can be passed in a
fixed arity call as an array of the type String[], or in a variable arity call as an element
in an implicitly created array of the type Object[]. Both calls are feasible and valid in
this case. Note that the compiler chooses a fixed arity call rather than a variable arity call,
but also issues a warning. The result at (9) confirms this course of action.
The array args of the type String[] is explicitly passed as an Object in a variable
arity call at (10), similar to the call at (7):
Click here to view code image
flexiPrint((Object) args);

// (10) Explicit varargs call

The array args of type String[] is explicitly passed as an array of the type
Object[] in a fixed arity call at (11). This call is equivalent to the call at (9), where the
widening reference conversion is implicit, but now without a warning at compile time.
The two calls print the same information, as is evident from the output at (9) and (11):
Click here to view code image
flexiPrint((Object[]) args);

3.7 The

// (11) Explicit non-varargs call

Method

The mechanics of compiling and running Java applications using the JDK are outlined in
§1.10, p. 16. The java command executes a method called main in the class specified
on the command line. Any class can have a main() method, but only the main()
method of the class specified in the java command starts the execution of a Java
application.
The main() method must have public accessibility so that the JVM can call this
method (§4.7, p. 123). It is a static method belonging to the class, so that no object of
the class is required to start the execution (§4.8, p. 132). It does not return a value; that is,
WOW! eBook
www.wowebook.org

it is declared as void (§6.4, p. 224). It always has an array of String objects as its only
formal parameter. This array contains any arguments passed to the program on the
command line (see the next subsection). The following method header declarations fit the
bill, and any one of them can be used for the main() method:
Click here to view code image
public static void main(String[] args)
public static void main(String… args)

// Method header
// Method header

The three modifiers can occur in any order in the method header. The requirements given
in these examples do not exclude specification of additional modifiers (§4.8, p. 131) or
any throws clause (§6.9, p. 251). The main() method can also be overloaded like any
other method (§3.2, p. 52). The JVM ensures that the main() method having the
previously mentioned method header is the starting point of program execution.

Program Arguments
Any arguments passed to the program on the command line can be accessed in the
main() method of the class specified on the command line:
>java Colors red green blue

These arguments are called program arguments. Note that the command name, java, and
the class name Colors are not passed to the main() method of the class Colors, nor
are any other options that are specified on the command line passed to this method.
Since the formal parameter of the main() method is an array of String objects,
individual String elements in the array can be accessed by using the [] operator.
In Example 3.12, the three arguments red, green, and blue can be accessed in the
main() method of the Colors class as args[0], args[1], and args[2],
respectively. The total number of arguments is given by the field length of the String
array args. Note that program arguments can be passed only as strings, and must be
explicitly converted to other values by the program, if necessary.
When no arguments are specified on the command line, an array of zero String
elements is created and passed to the main() method. Thus the reference value of the
formal parameter in the main() method is never null.
Program arguments supply information to the application, which can be used to tailor the
runtime behavior of the application according to user requirements.

WOW! eBook
www.wowebook.org

Example 3.12

Passing Program Arguments

Click here to view code image
public class Colors {
public static void main(String[] args) {
System.out.println(“No. of program arguments: ” + args.length);
for (int i = 0; i < args.length; i++)
System.out.println(“Argument no. ” + i + ” (” + args[i] + “) has ” +
args[i].length() + ” characters.”);
}
}

Running the program:
Click here to view code image
>java Colors red green blue
No. of program arguments: 3
Argument no. 0 (red) has 3 characters.
Argument no. 1 (green) has 5 characters.
Argument no. 2 (blue) has 4 characters.

3.8 Enumerated Types
In this section we provide a basic introduction to 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 constants is to declare them as final, static variables in a class (or
interface) declaration:
Click here to view code image
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 type-safe, 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 a special kind of class type that is much more powerful than
the approach outlined earlier for defining collections of named constants.

Declaring Type-safe Enums
The canonical form of declaring an enum type is shown here:
Click here to view code image
public enum MachineState
{
BUSY, IDLE, BLOCKED

// Enum header
// Enum body
// Enum constants
WOW! eBook
www.wowebook.org

}

The keyword enum is used to declare an enum type, as opposed to the keyword class
for a class declaration. The basic notation requires the enum type name in enum header,
and a comma-separated list of enum constants can be specified in the enum body.
Optionally, an access modifier can also be specified in the enum header, as for a (toplevel) class. In the example enum declaration, the name of the enum type is
MachineState. It defines three enum constants with explicit names. 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 type-safe manner.
Other member declarations can be specified in the body of an enum type, but the
canonical form suffices for the purpose of this book. Analogous to a class declaration, an
enum type is compiled to Java bytecode that is placed in a separate class file.
The enum types java.time.Month and java.time.DayOfWeek are two examples
of enum types from the Java SE platform API. As we would expect, the Month enum
type represents the months from JANUARY to DECEMBER, and the DayOfWeek enum
type represents the days of the week from MONDAY to SUNDAY. Examples of their usage
can be found in §11.2, p. 462.
Some additional examples of enum types follow:
Click here to view code image
public enum MarchingOrders { LEFT, RIGHT }
public enum TrafficLightState { RED, YELLOW, GREEN }
enum MealType { BREAKFAST, LUNCH, DINNER }

Using Type-safe Enums
Example 3.13 illustrates the use of enum constants. An enum type is essentially used in
the same way as any other reference type. Enum constants are actually public,
static, final fields of the enum type, and they are implicitly initialized with instances
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 or an interface.
Example 3.13 shows a machine client that uses a machine whose state is an enum
constant. In this example, 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).
WOW! eBook
www.wowebook.org

Example 3.13

Using Enums

Click here to view code image
// File: MachineState.java
public enum MachineState { BUSY, IDLE, BLOCKED }
// File: Machine.java
public class Machine {
private MachineState state;
public void setState(MachineState state) { this.state = state; }
public MachineState getState() { return this.state; }
}
// File: MachineClient.java
public class MachineClient {
public static void main(String[] args) {
Machine machine = new Machine();
machine.setState(MachineState.IDLE);
// machine.setState(1);
error!

// (1) Passed as a value.
// (2) Compile-time

MachineState state = machine.getState();
reference.
System.out.println(
“Current machine state: ” + state
name.
);

// (3) Declaring a

// MachineState newState = new MachineState();
error!

// (5) Compile-time

// (4) Printing the enum

System.out.println(“All machine states:”);
for (MachineState ms : MachineState.values()) { // (6) Traversing over
enum
System.out.println(ms + “:” + ms.ordinal());

//

contants.

}
System.out.println(“Comparison:”);
MachineState state1 = MachineState.BUSY;
MachineState state2 = state1;
MachineState state3 = MachineState.BLOCKED;
System.out.println(state1 + ” == ” + state2 + “: ” +
(state1 == state2));
System.out.println(state1 + ” is equal to ” + state2 + “: ” +
(state1.equals(state2)));
System.out.println(state1 + ” is less than ” + state3 + “: ” +
(state1.compareTo(state3) < 0));
}
}

Output from the program:
Click here to view code image
Current machine state: IDLE
All machine states:
BUSY:0
IDLE:1
WOW! eBook
www.wowebook.org

// (7)
// (8)
// (9)

BLOCKED:2
Comparison:
BUSY == BUSY: true
BUSY is equal to BUSY: true
BUSY is less than BLOCKED: true

Selected Methods for Enum Types
All enum types implicitly have the following useful method:
Click here to view code image
static EnumTypeName[] values()

Returns an array containing the enum constants of this enum type, in the order they
are specified.
The loop at (6) in Example 3.13 illustrates traversing over all the MachineState enum
constants in the order they are specified. An array containing all the MachineState
constants is obtained by calling the static method values() on the enum type.
All enum types are subtypes of the java.lang.Enum class, which provides the default
behavior. All enum types inherit the following selected methods from the
java.lang.Enum class:
Click here to view code image
final boolean equals(Object other)

This method returns true if the specified object is equal to this enum constant.
final int compareTo(E other)

The natural order of the enum constants in an enum type is based on their ordinal
values (see the ordinal() method next). The compareTo() method of the
Comparable interface returns the value zero if this enum constant is equal to the
other enum constant, a value less than zero if this enum constant is less than the
other enum constant, or a value greater than zero if this enum constant is greater
than the other enum constant.
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.
Note that the equality test implemented by the equals() method is based on reference
equality (==) of the enum constants, not on value equality. 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 constant—in other
words, whether the references are aliases. Thus, for any two enum references state1
WOW! eBook
www.wowebook.org

and state2, the expressions state1.equals(state2) and state1 == state2
are equivalent, as shown at (7) and (8) in Example 3.13.
The ordinal value of the constants in an enum type determines the result of comparing
such constants with the compareTo() method, as shown at (9) in Example 3.13.

Review Questions
3.13 What will the following program print when run?
Click here to view code image
public class ParameterPass {
public static void main(String[] args) {
int i = 0;
addTwo(i++);
System.out.println(i);
}
static void addTwo(int i) {
i += 2;
}
}

Select the one correct answer.
(a) 0
(b) 1
(c) 2
(d) 3
3.14 What will be the result of compiling and running the following program?
Click here to view code image
public class Passing
public static void
int a = 0; int b
int[] bArr = new

{
main(String[] args) {
= 0;
int[1]; bArr[0] = b;

inc1(a); inc2(bArr);
System.out.println(“a=” + a + ” b=” + b + ” bArr[0]=” + bArr[0]);
}
public static void inc1(int x) { x++; }
public static void inc2(int[] x) { x[0]++; }
}

Select the one correct answer.
(a) The code will fail to compile, since x[0]++; is not a legal statement.
(b) The code will compile and will print a=1 b=1 bArr[0]=1 at runtime.
(c) The code will compile and will print a=0 b=1 bArr[0]=1 at runtime.
(d) The code will compile and will print a=0 b=0 bArr[0]=1 at runtime.
WOW! eBook
www.wowebook.org

(e) The code will compile and will print a=0 b=0 bArr[0]=0 at runtime.
3.15 Which statements, when inserted at (1), will result in a compile-time error?
Click here to view code image
public class ParameterUse {
static void main(String[] args) {
int a = 0;
final int b = 1;
int[] c = { 2 };
final int[] d = { 3 };
useArgs(a, b, c, d);
}
static void useArgs(final int a, int b, final int[] c, int[] d) {
// (1) INSERT STATEMENT HERE.
}
}

Select the two correct answers.
(a) a++;
(b) b++;
(c) b = a;
(d) c[0]++;
(e) d[0]++;
(f) c = d;
3.16 Which of the following method declarations are valid declarations?
Select the three correct answers.
(a) void compute(int… is) { }
(b) void compute(int is…) { }
(c) void compute(int… is, int i, String… ss) { }
(d) void compute(String… ds) { }
(e) void compute(String… ss, int len) { }
(f) void compute(char[] ca, int… is) { }
3.17 Given the following code:
Click here to view code image
public class RQ810A40 {
static void print(Object… obj) {
System.out.println(“Object…: ” + obj[0]);
}
public static void main(String[] args) {
// (1) INSERT METHOD CALL HERE.
}
}

Which method call, when inserted at (1), will not result in the following output
WOW! eBook
www.wowebook.org

from the program:
Object…: 9

Select the one correct answer.
(a) print("9", "1", "1");
(b) print(9, 1, 1);
(c) print(new int[] {9, 1, 1});
(d) print(new Integer[] {9, 1, 1});
(e) print(new String[] {"9", "1", "1"});
(f) print(new Object[] {"9", "1", "1"});
(g) None of the above.

Chapter Summary
The following topics were covered in this chapter:
• An overview of declarations that can be specified in a class
• Declaration of methods, usage of the this reference in an instance method, and
method overloading
• Declaration of constructors, usage of the default constructor, and overloading of
constructors
• Explanation of declaration, construction, initialization, and usage of both onedimensional and multidimensional arrays, including anonymous arrays
• Sorting and searching arrays
• Parameter passing, both primitive values and object references, including arrays and
array elements; and declaring final parameters
• Declaring and calling methods with variable arity
• Declaration of the main() method whose execution starts the application
• Passing program arguments to the main() method
• Declaring and using simple enum types

Programming Exercise
3.1 Write a program to grade a short multiple-choice quiz. The correct answers for the
quiz are
1.
2.
3.
4.

C
A
B
D

5.
6.
7.
8.

B
C
C
A
WOW! eBook
www.wowebook.org

Assume that the passing marks are at least 5 out of 8. The program stores the
correct answers in an array. The submitted answers are specified as program
arguments. Let X represent a question that was not answered on the quiz. Use an
enum type to represent the result of answering a question.
Example of running the program:
Click here to view code image
>java QuizGrader C B B D B C A X
Question Submitted Ans. Correct Ans. Result
1
C
C
CORRECT
2
B
A
WRONG
3
B
B
CORRECT
4
D
D
CORRECT
5
B
B
CORRECT
6
C
C
CORRECT
7
A
C
WRONG
8
X
A
UNANSWERED
No. of correct answers:
5
No. of wrong answers:
2
No. of questions unanswered: 1
The candidate PASSED.

WOW! eBook
www.wowebook.org

4. Access Control

4.1 Java Source File Structure
The structure of a skeletal Java source file is depicted in Figure 4.1. A Java source file can
have the following elements that, if present, must be specified in the following order:
1. An optional package declaration to specify a package name. Packages are
discussed in §4.2.
2. Zero or more import declarations. Since import declarations introduce type or
static member names in the source code, they must be placed before any type
declarations. Both type and static import declarations are discussed in §4.2.
3. Any number of top-level type declarations. Class, enum, and interface declarations
are collectively known as type declarations. Since these declarations belong to the
same package, they are said to be defined at the top level, which is the package level.
The type declarations can be defined in any order. Technically, a source file need not
have any such declarations, but that is hardly useful.
The JDK imposes the restriction that at most one public class declaration per
WOW! eBook
www.wowebook.org

source file can be defined. If a public class is defined, the file name must match
this public class. For example, if the public class name is NewApp, the file
name must be NewApp.java.
Classes are discussed in §3.1, p. 48; enums are discussed in §3.8, p. 87; and
interfaces are discussed in §7.6, p. 290.

Figure 4.1

Java Source File Structure

Note that except for the package and the import statements, all code is encapsulated
in classes, interfaces, and enums. No such restriction applies to comments and whitespace.

4.2 Packages
A package in Java is an encapsulation mechanism that can be used to group related
classes, interfaces, enums, and subpackages.
Figure 4.2 shows an example of a package hierarchy, comprising a package called
wizard that contains two other packages: pandorasbox and spells. The package
pandorasbox has a class called Clown that implements an interface called Magic,
also found in the same package. In addition, the package pandorasbox has a class
called LovePotion and a subpackage called artifacts containing a class called
Ailment. The package spells has two classes: Baldness and LovePotion. The
class Baldness is a subclass of class Ailment found in the subpackage artifacts
in the package pandorasbox.

WOW! eBook
www.wowebook.org

Figure 4.2

Package Hierarchy

The dot (.) notation is used to uniquely identify package members in the package
hierarchy. The class wizard.pandorasbox.LovePotion, for example, is different
from the class wizard.spells.LovePotion. The Ailment class can be easily
identified by the name wizard.pandorasbox.artifacts.Ailment, which is
known as the fully qualified name of the type. Note that the fully qualified name of the
type in a named package comprises the fully qualified name of the package and the simple
name of the type. The simple type name Ailment and the fully qualified package name
wizard.pandorasbox.artifacts together define the fully qualified type name
wizard.pandorasbox.artifacts.Ailment. Analogously, the fully qualified
name of a subpackage comprises the fully qualified name of the parent package and the
simple name of the subpackage.
Java programming environments usually map the fully qualified name of packages to the
underlying (hierarchical) file system. For example, on a Unix system, the class file
LovePotion.class corresponding to the fully qualified name
wizard.pandorasbox.LovePotion would be found under the directory
wizard/pandorasbox.
Conventionally, a global naming scheme based on the Internet domain names is used to
uniquely identify packages. If the package wizard was implemented by a company
called Sorcerers Limited that owns the domain sorcerersltd.com, its fully qualified
name would be
com.sorcerersltd.wizard

Because domain names are unique, packages with this naming scheme are globally
identifiable. It is not advisable to use the top-level package names java and sun, as
these are reserved for the Java designers.
The subpackage wizard.pandorasbox.artifacts could easily have been placed
WOW! eBook
www.wowebook.org

elsewhere, as long as it was uniquely identified. Subpackages in a package do not affect
the accessibility of the other package members. For all intents and purposes, subpackages
are more an organizational feature rather than a language feature. Accessibility of
members in a package is discussed in §4.4. Accessibility of members defined in type
declarations is discussed in §4.7.

Defining Packages
A package hierarchy represents an organization of the Java classes and interfaces. It does
not represent the source code organization of the classes and interfaces. The source code is
of no consequence in this regard. Each Java source file (also called compilation unit) can
contain zero or more type declarations, but the compiler produces a separate class file
containing the Java bytecode for each of them. A type declaration can indicate that its Java
bytecode should be placed in a particular package, using a package declaration.
The package statement has the following syntax:
Click here to view code image
package fully_qualified_package_name;

At most one package declaration can appear in a source file, and it must be the first
statement in the source file. The package name is saved in the Java bytecode for the types
contained in the package. Java naming conventions recommend writing package names in
lowercase letters.
Note that this scheme has two consequences. First, all the classes and interfaces in a
source file will be placed in the same package. Second, several source files can be used to
specify the contents of a package.
If a package declaration is omitted in a compilation unit, the Java bytecode for the
declarations in the compilation unit will belong to an unnamed package (also called the
default package), which is typically synonymous with the current working directory on the
host system.
Example 4.1 illustrates how the packages in Figure 4.2 can be defined using the package
declaration. There are four compilation units. Each compilation unit has a package
declaration, ensuring that the type declarations are compiled into the correct package. The
complete code can be found in Example 4.8 on page 118.

WOW! eBook
www.wowebook.org

Example 4.1

Defining Packages and Using Type Import

Click here to view code image
// File name: Clown.java
package wizard.pandorasbox;

// Package declaration

import wizard.pandorasbox.artifacts.Ailment; // Importing specific class
public class Clown implements Magic { /* … */ }
interface Magic { /* … */ }
// File name: LovePotion.java
package wizard.pandorasbox;

// Package declaration

public class LovePotion { /* … */
// File name: Ailment.java
package wizard.pandorasbox.artifacts;

// Package declaration

public class Ailment { /* … */ }
// File name: Baldness.java
package wizard.spells;

// Package declaration

import wizard.pandorasbox.*;
import wizard.pandorasbox.artifacts.*;

// (1) Type-import-on-demand
// (2) Import from subpackage

public class Baldness extends Ailment {
wizard.pandorasbox.LovePotion tlcOne;
name
LovePotion tlcTwo;
// …
}

// Simple name for Ailment
// (3) Fully qualified class
// Class in same package

class LovePotion { /* … */ }

Using Packages
The import facility in Java makes it easier to use the contents of packages. This subsection
discusses importing reference types and static members of reference types from packages.
Importing Reference Types
The accessibility of types (classes, interfaces, and enums) in a package determines their
access from other packages. Given a reference type that is accessible from outside a
package, the reference type can be accessed in two ways. One way is to use the fully
qualified name of the type. However, writing long names can become tedious. The second
way is to use the import declaration that provides a shorthand notation for specifying
the name of the type, often called type import.
The import declarations must be the first statement after any package declaration in a
source file. The simple form of the import declaration has the following syntax:
Click here to view code image
WOW! eBook
www.wowebook.org

import fully_qualified_type_name;

This is called single-type-import. As the name implies, such an import declaration
provides a shorthand notation for a single type. The simple name of the type (that is, its
identifier) can now be used to access this particular type. Given the import declaration
Click here to view code image
import wizard.pandorasbox.Clown;

the simple name Clown can be used in the source file to refer to this class.
Alternatively, the following form of the import declaration can be used:
Click here to view code image
import fully_qualified_package_name.*;

This is called type-import-on-demand. It allows any type from the specified package to be
accessed by its simple name.
An import declaration does not recursively import subpackages. The declaration also
does not result in inclusion of the source code of the types; rather, it simply imports type
names (that is, it makes type names available to the code in a compilation unit).
All compilation units implicitly import the java.lang package (§8.1, p. 342). This is
the reason why we can refer to the class String by its simple name, and need not use its
fully qualified name java.lang.String all the time.
Example 4.1 shows several usages of the import statement. Here we will draw attention
to the class Baldness in the file Baldness.java. This class relies on two classes that
have the same simple name LovePotion but are in different packages:
wizard.pandorasbox and wizard.spells, respectively. To distinguish between
the two classes, we can use their fully qualified names. However, since one of them is in
the same package as the class Baldness, it is enough to fully qualify the class from the
other package. This solution is used in Example 4.1 at (3). Note that the import of the
wizard.pandorasbox package at (1) becomes redundant. Such name conflicts can
usually be resolved by using variations of the import statement together with fully
qualified names.
The class Baldness extends the class Ailment, which is in the subpackage
artifacts of the wizard.pandorasbox package. The import declaration at (2)
is used to import the types from the subpackage artifacts.
The following example shows how a single-type-import declaration can be used to
disambiguate a type name when access to the type is ambiguous by its simple name. The
following import statement allows the simple name List to be used as shorthand for
the java.awt.List type as expected:
Click here to view code image
import java.awt.*;

// imports all reference types from java.awt

Given the two import declarations
Click here to view code image
WOW! eBook
www.wowebook.org

import java.awt.*;
import java.util.*;

// imports all type names from java.awt
// imports all type names from java.util

the simple name List is now ambiguous, because both the types java.util.List
and java.awt.List match.
Adding a single-type-import declaration for the java.awt.List type allows the simple
name List to be used as a shorthand notation for this type:
Click here to view code image
import java.awt.*;
import java.util.*;
import java.awt.List;
explicitly

// imports all type names from java.awt
// imports all type names from java.util
// imports the type List from java.awt

Importing Static Members of Reference Types
Analogous to the type import facility, Java also allows import of static members of
reference types from packages, often called static import.
Static import allows accessible static members declared in a type to be imported, so that
they can be used by their simple names, and therefore need not be qualified. The import
applies to the whole compilation unit, and importing from the unnamed package is not
permissible.
The two forms of static import are shown here:
Click here to view code image
// Single-static-import: imports a specific static member from the designated
type
import static fully_qualified_type_name.static_member_name;
// Static-import-on-demand: imports all static members in the designated type
import static fully_qualified_type_name.*;

Both forms require the use of the keyword import followed by the keyword static,
although the feature is called static import. In both cases, the fully qualified name of the
reference type we are importing from is required.
The first form allows single static import of individual static members, and is
demonstrated in Example 4.2. The constant PI, which is a static field in the
class java.lang.Math, is imported at (1). Note the use of the fully qualified name of
the type in the static import statement. The static method named sqrt from the
class java.lang.Math is imported at (2). Only the name of the static method is
specified in the static import statement; no parameters are listed. Use of any other static
member from the Math class requires that the fully qualified name of the class be
specified. Since types from the java.lang package are imported implicitly, the fully
qualified name of the Math class is not necessary, as shown at (3).
Static import on demand is easily demonstrated by replacing the two import statements
in Example 4.2 by the following import statement:
Click here to view code image
import static java.lang.Math.*;
WOW! eBook
www.wowebook.org

We can also dispense with the use of the class name Math in (3), as all static members
from the Math class are now imported:
Click here to view code image
double hypotenuse = hypot(x, y);
Example 4.2

// (3’) Type name can now be omitted.

Single Static Import

Click here to view code image
import static java.lang.Math.PI;
// (1) Static field
import static java.lang.Math.sqrt;
// (2) Static method
// Only specified static members are imported.
public class Calculate3 {
public static void main(String[] args) {
double x = 3.0, y = 4.0;
double squareroot = sqrt(y);
// Simple name of static method
double hypotenuse = Math.hypot(x, y); // (3) Requires type name
double area = PI * y * y;
// Simple name of static field
System.out.printf(“Square root: %.2f, hypotenuse: %.2f, area: %.2f%n”,
squareroot, hypotenuse, area);
}
}

Output from the program:
Click here to view code image
Square root: 2.00, hypotenuse: 5.00, area: 50.27

Example 4.3 illustrates how static import can be used to access interface constants (§7.6,
p. 302). The static import statement at (1) allows the interface constants in the package
mypkg to be accessed by their simple names. The static import facility avoids the
MyFactory class having to implement the interface so as to access the constants by their
simple name (often referred to as the interface constant antipattern):
Click here to view code image
public class MyFactory implements mypkg.IMachineState {
// …
}

WOW! eBook
www.wowebook.org

Example 4.3

Avoiding the Interface Constant Antipattern

Click here to view code image
package mypkg;
public interface IMachineState {
// Fields are public, static and final.
int BUSY = 1;
int IDLE = 0;
int BLOCKED = -1;
}
import static mypkg.IMachineState.*;
constants

// (1) Static import interface

public class MyFactory {
public static void main(String[] args) {
int[] states = { IDLE, BUSY, IDLE, BLOCKED };
for (int s : states)
System.out.print(s + ” “);
}
}

Output from the program:
0 1 0 -1

Static import is ideal for importing enum constants from packages, as such constants are
static members of an enum type. Example 4.4 combines type and static imports. The enum
constants can be accessed at (5) using their simple names because of the static import
statement at (2). The type import at (1) is required to access the enum type State by its
simple name at (4) and (6).

WOW! eBook
www.wowebook.org

Example 4.4

Importing Enum Constants

Click here to view code image
package mypkg;
public enum State { BUSY, IDLE, BLOCKED }
// File: Factory.java (in unnamed package)
import mypkg.State;
// (1) Single type import
import static mypkg.State.*;
import static java.lang.System.out;

// (2) Static import on demand
// (3) Single static import

public class Factory {
public static void main(String[] args) {
State[] states = {
// (4) Using type import implied by (1)
IDLE, BUSY, IDLE, BLOCKED
// (5) Using static import implied by
(2)
};
for (State s : states)
// (6) Using type import implied by (1)
out.print(s + ” “);
// (7) Using static import implied by
(3)
}
}

Output from the program:
IDLE BUSY IDLE BLOCKED

Identifiers in a class can shadow static members that are imported. Example 4.5 illustrates
the case where the parameter out of the method writeInfo() has the same name as
the statically imported field java.lang.System.out. The type of the parameter is
ShadowImport and that of the statically imported field is PrintStream. Both classes
PrintStream and ShadowImport define the method println() that is called in
the program. The only way to access the imported field out in the method
writeInfo() is to use its fully qualified name.

WOW! eBook
www.wowebook.org

Example 4.5

Shadowing Static Import

Click here to view code image
import static java.lang.System.out;

// (1) Static import

public class ShadowImport {
public static void main(String[] args) {
out.println(“Calling println() in java.lang.System.out”);
ShadowImport sbi = new ShadowImport();
writeInfo(sbi);
}
// Parameter shadows java.lang.System.out:
public static void writeInfo(ShadowImport out) {
out.println(“Calling println() in the parameter out”);
System.out.println(“Calling println() in java.lang.System.out”); //
Qualify
}
public void println(String msg) {
out.println(msg + ” of type ShadowImport”);
}
}

Output from the program:
Click here to view code image
Calling println() in java.lang.System.out
Calling println() in the parameter out of type ShadowImport
Calling println() in java.lang.System.out

The next code snippet illustrates a common conflict that occurs when a static field with the
same name is imported by several static import statements. This conflict is readily
resolved by using the fully qualified name of the field. In the case shown here, we can use
the simple name of class in which the field is declared, as the java.lang package is
implicitly imported by all compilation units.
Click here to view code image
import static java.lang.Integer.MAX_VALUE;
import static java.lang.Double.MAX_VALUE;
public class StaticFieldConflict {
public static void main(String[] args) {
System.out.println(MAX_VALUE);
error!
System.out.println(Integer.MAX_VALUE);
System.out.println(Double.MAX_VALUE);
}
}

// (1) Ambiguous! Compile-time
// OK
// OK

Conflicts can also occur when a static method with the same signature is imported by
several static import statements. In Example 4.6, a method named binarySearch is
imported 21 times by the static import statements. This method is overloaded twice in the
java.util.Collections class and 18 times in the java.util.Arrays class, in
addition to one declaration in the mypkg.Auxiliary class. The classes
java.util.Arrays and mypkg.Auxiliary have a declaration of this method with
WOW! eBook
www.wowebook.org

the same signature that matches the method call at (2), resulting in a signature conflict that
is flagged as a compile-time error. The conflict can again be resolved by specifying the
fully qualified name of the method.
If the static import statement at (1) is removed, there is no conflict, as only the class
java.util.Arrays has a method that matches the method call at (2). If the
declaration of the method binarySearch() at (3) is allowed, there is also no conflict,
as this method declaration will shadow the imported method whose signature it matches.
Example 4.6

Conflict in Importing Static Method with the Same Signature

Click here to view code image
package mypkg;
public class Auxiliary {
public static int binarySearch(int[] a, int key) { // Same in
java.util.Arrays
// Implementation is omitted.
return -1;
}
}
// File: MultipleStaticImport.java (in unnamed package)
import static java.util.Collections.binarySearch; //
2 overloaded methods
import static java.util.Arrays.binarySearch;
// + 18 overloaded methods
import static mypkg.Auxiliary.binarySearch; // (1) Causes signature conflict
public class MultipleStaticImport {
public static void main(String[] args) {
int index = binarySearch(new int[] {10, 50, 100}, 50); // (2) Ambiguous!
System.out.println(index);
}
//public static int binarySearch(int[] a, int key) {
// return -1;
//}
}

// (3)

Compiling Code into Packages
Conventions for specifying pathnames vary on different platforms. In this chapter, we will
use pathname conventions used on a Unix platform. While trying out the examples in this
section, attention should be paid to platform dependencies in this regard—especially the
fact that the separator characters in file paths for the Unix and Windows platforms are /
and \, respectively.
As mentioned earlier, a package can be mapped on a hierarchical file system. We can think
of a package name as a pathname in the file system. Referring to Example 4.1, the
package name wizard.pandorasbox corresponds to the pathname
wizard/pandorasbox. The Java bytecode for all types declared in the source files
Clown.java and LovePotion.java will be placed in the package directory with the
pathname wizard/pandorasbox, as these source files have the following package
declaration:
WOW! eBook
www.wowebook.org

package wizard.pandorasbox;

The location in the file system where the package directory should be created is specified
using the d option (d for destination) of the javac command. The term destination
directory is a synonym for this location in the file system. The compiler will create the
package directory with the pathname wizard/pandorasbox (including any
subdirectories required) under the specified location, and place the Java bytecode for the
types declared in the source files Clown.java and LovePotion.java inside the
package directory.
Assuming that the current directory (.) is the directory /pgjc/work, and the four
source files in Example 4.1 are found in this directory, the following command issued in
the current directory will create a file hierarchy under this directory (Figure 4.3) that
mirrors the package hierarchy in Figure 4.2:
Click here to view code image
>javac -d . Clown.java LovePotion.java Ailment.java Baldness.java

WOW! eBook
www.wowebook.org

Figure 4.3

File Hierarchy

Note the subdirectories that are created for a fully qualified package name, and where the
class files are located. In this command line, the space between the -d option and its
argument is mandatory.
We can specify any relative pathname that designates the destination directory, or its
absolute pathname:
Click here to view code image
>javac -d /pgjc/work Clown.java LovePotion.java Ailment.java Baldness.java

We can, of course, specify destinations other than the current directory where the class
files with the bytecode should be stored. The following command in the current directory
/pgjc/work will create the necessary packages with the class files under the destination
WOW! eBook
www.wowebook.org

directory /pgjc/myapp:
Click here to view code image
>javac -d ../myapp Clown.java LovePotion.java Ailment.java Baldness.java

Without the -d option, the default behavior of the javac compiler is to place all class
files directly under the current directory (where the source files are located), rather than in
the appropriate subdirectories corresponding to the packages.
The compiler will report an error if there is any problem with the destination directory
specified with the -d option (e.g., if it does not exist or does not have the right file
permissions).

Running Code from Packages
Referring to Example 4.1, if the current directory has the absolute pathname
/pgjc/work and we want to run Clown.class in the directory with the pathname
./wizard/pandorasbox, the fully qualified name of the Clown class must be
specified in the java command:
Click here to view code image
>java wizard.pandorasbox.Clown

This will load the bytecode of the class Clown from the file with the pathname
./wizard/pandorasbox/Clown.class, and start the execution of its main()
method.

4.3 Searching for Classes
The documentation for the JDK tools explains how to organize packages in more elaborate
schemes. In particular, the CLASSPATH environment variable can be used to specify the
class search path (usually abbreviated to just class path), which are pathnames or
locations in the file system where JDK tools should look when searching for classes and
other resource files. Alternatively, the -classpath option (often abbreviated to -cp) of
the JDK tool commands can be used for the same purpose. The CLASSPATH environment
variable is not recommended for this purpose, as its class path value affects all Java
applications on the host platform, and any application can modify it. However, the -cp
option can be used to set the class path for each application individually. This way, an
application cannot modify the class path for other applications. The class path specified in
the -cp option supersedes the path or paths set by the CLASSPATH environment variable
while the JDK tool command is running. We will not discuss the CLASSPATH
environment variable here, and assume it to be undefined.
Basically, the JDK tools first look in the directories where the Java standard libraries are
installed. If the class is not found in the standard libraries, the tool searches in the class
path. When no class path is defined, the default value of the class path is assumed to be
the current directory. If the -cp option is used and the current directory should be
searched by the JDK tool, the current directory must be specified as an entry in the class
path, just like any other directory that should be searched. This is most conveniently done
WOW! eBook
www.wowebook.org

by including '.' as one of the entries in the class path.
We will use the file hierarchies shown in Figure 4.4 to illustrate some of the intricacies
involved when searching for classes. The current directory has the absolute pathname
/top/src, where the source files are stored. The package pkg will be created under the
directory with the absolute pathname /top/bin. The source code in the two source files
A.java and B.java is also shown in Figure 4.4.

Figure 4.4

Searching for Classes

The file hierarchy before any files are compiled is shown in Figure 4.4a. Since the class B
does not use any other classes, we compile it first with the following command, resulting
in the file hierarchy shown in Figure 4.4b:
>javac -d ../bin B.java

Next, we try to compile the file A.java, and get the following results:
>javac -d ../bin A.java
A.java:3: cannot find symbol
symbol : class B
location: class pkg.A
public class A { B b; }
^
1 error

The compiler cannot find the class B—that is, the file B.class containing the Java
bytecode for the class B. In Figure 4.4b, we can see that it is in the package pkg under the
directory bin, but the compiler cannot find it. This is hardly surprising, as there is no
WOW! eBook
www.wowebook.org

bytecode file for the class B in the current directory, which is the default value of the class
path. The following command sets the value of the class path to be /top/bin, and
compilation is successful (Figure 4.4c):
Click here to view code image
>javac -cp /top/bin -d ../bin A.java

It is very important to understand that when we want the JDK tool to search in a named
package, it is the location of the package that is specified; in other words, the class path
indicates the directory that contains the first element of the fully qualified package name.
In Figure 4.4c, the package pkg is contained under the directory whose absolute path is
/top/bin. The following command will not work, as the directory /top/bin/pkg
does not contain a package with the name pkg that has a class B:
Click here to view code image
>javac -cp /top/bin/pkg -d ../bin A.java

Also, the compiler is not using the class path to find the source file(s) that are specified in
the command line. In the preceding command, the source file has the relative pathname
./A.java. Consequently, the compiler looks for the source file in the current directory.
The class path is used to find the classes used by the class A.
Given the file hierarchy in Figure 4.3, the following -cp option sets the class path so that
all packages (wizard.pandorasbox, wizard.pandorasbox.artifacts,
wizard.spells) in Figure 4.3 will be searched, as all packages are located under the
specified directory:
-cp /pgjc/work

However, the following -cp option will not help in finding any of the packages in Figure
4.3, as none of the packages are located under the specified directory:
Click here to view code image
>java -cp /pgjc/work/wizard pandorasbox.Clown

This command also illustrates an important point about package names: The fully qualified
package name should not be split. The package name for the class
wizard.pandorasbox.Clown is wizard.pandorasbox, and must be specified
fully. The following command will search all packages in Figure 4.3 for classes that are
used by the class wizard.pandorasbox.Clown:
Click here to view code image
>java -cp /pgjc/work wizard.pandorasbox.Clown

The class path can specify several entries (i.e., several locations), and the JDK tool
searches them in the order they are specified, from left to right.
-cp /pgjc/work:/top/bin:.

We have used the path-separator character ':' for Unix platforms to separate the entries,
and also included the current directory (.) as an entry. There should be no whitespace on
either side of the path-separator character.
The search in the class path entries stops once the required class file is found. Therefore,
WOW! eBook
www.wowebook.org

the order in which entries are specified can be significant. If a class B is found in a
package pkg located under the directory /ext/lib1, and also in a package pkg located
under the directory /ext/lib2, the order in which the entries are specified in the two cp options shown next is significant. They will result in the class pkg.B being found
under /ext/lib1 and /ext/lib2, respectively.
-cp /ext/lib1:/ext/lib2
-cp /ext/lib2:/ext/lib1

The examples so far have used absolute pathnames for class path entries. We can, of
course, use relative pathnames as well. If the current directory has the absolute pathname
/pgjc/work in Figure 4.3, the following command will search the packages under the
current directory:
Click here to view code image
>java -cp . wizard.pandorasbox.Clown

If the current directory has the absolute pathname /top/src in Figure 4.4, the following
command will compile the file ./A.java:
Click here to view code image
>javac -cp ../bin -d ../bin A.java

If the name of an entry in the class path includes whitespace, the name should be double
quoted so that it will be interpreted correctly:
-cp “../new bin”

Review Questions
4.1 Given the source file A.java:
// File: A.java
package net.alphabet;
import java.util.ArrayList;
public class A {}
class B {}

Select the two correct answers.
(a) Both class A and class B will be placed in the package net.alphabet.
(b) Only class A will be placed in the package net.alphabet. Class B will be
placed in the default package.
(c) Both class A and class B can access the imported class
java.util.ArrayList by its simple name.
(d) Only class A can access the imported class java.util.ArrayList by its
simple name.
4.2 Which import statement, when inserted independently at (1), will make the code
compile?
Click here to view code image
// File: Window.java
WOW! eBook
www.wowebook.org

package app;
public class Window {
final static String frame = “Top-frame”;
}
___________________________________________________________________________
// File: Canvas.java
package app;
// (1) INSERT IMPORT STATEMENT HERE.
public class Canvas {
private String str = frame;
}

Select the one correct answer.
(a) import app.*;
(b) import app.Window;
(c) import java.lang.*;
(d) import java.lang.String;
(e) import static app.Window.frame;
4.3 Which import statements, when inserted independently at (1), will make the code
compile?
Click here to view code image
// File: Window.java
package mainpkg.subpkg1;
public class Window {}
___________________________________________________________________________
// File: Window.java
package mainpkg.subpkg2;
public class Window {}
___________________________________________________________________________
// File: Screen.java
package mainpkg;
// (1) INSERT IMPORT STATEMENTS HERE.
public class Screen {
private Window win;
}

Select the four correct answers.
(a) import mainpkg.*;
(b) import mainpkg.subpkg1.*;
(c) import mainpkg.subpkg2.*;
(d)
Click here to view code image
import mainpkg.subpkg1.*;
import mainpkg.subpkg2.Window;
WOW! eBook
www.wowebook.org

(e)
Click here to view code image
import mainpkg.subpkg1.Window;
import mainpkg.subpkg2.*;

(f)
import mainpkg.subpkg1.*;
import mainpkg.subpkg2.*;

(g)
Click here to view code image
import mainpkg.subpkg1.Window;
import mainpkg.subpkg2.Window;

4.4 Given the following code:
Click here to view code image
// (1) INSERT ONE IMPORT STATEMENT HERE
public class RQ700A20 {
public static void main(String[] args) {
System.out.println(sqrt(49));
}
}

Which import statements, when inserted independently at (1), will make the
program print 7, when the program is compiled and run?
Select the two correct answers.
(a) import static Math.*;
(b) import static Math.sqrt;
(c) import static java.lang.Math.sqrt;
(d) import static java.lang.Math.sqrt();
(e) import static java.lang.Math.*;
4.5 Given the source file A.java:
package top.sub;
public class A {}

and the following directory hierarchy:
Click here to view code image
/proj
|– src
|
|– top
|
|– sub
|
|– A.java
|– bin

Assuming that the current directory is /proj/src, which of the following
statements are true?
Select the three correct answers.
WOW! eBook
www.wowebook.org

(a) The following command will compile, and place the bytecode of the class
top.sub.A under /proj/bin:
javac -d . top/sub/A.java

(b) The following command will compile, and place the bytecode of the class
top.sub.A under /proj/bin:
Click here to view code image
javac -d /proj/bin top/sub/A.java

(c) The following command will compile, and place the bytecode of the class
top.sub.A under /proj/bin:
Click here to view code image
javac -D /proj/bin ./top/sub/A.java

(d) The following command will compile, and place the bytecode of the class
top.sub.A under /proj/bin:
Click here to view code image
javac -d ../bin top/sub/A.java

(e) After successful compilation, the absolute pathname of the file A.class will
be:
/proj/bin/A.class

(f) After successful compilation, the absolute pathname of the file A.class will
be:
/proj/bin/top/sub/A.class

4.6 Given the following directory structure:
Click here to view code image
/top
|– wrk
|– pkg
|– A.java
|– B.java

Assume that the two files A.java and B.java contain the following code,
respectively:
Click here to view code image
// File: A.java
package pkg;
class A { B b; }
___________________________________________________________________________
// File: B.java
package pkg;
class B {…}

For which combinations of current directory and command is the compilation
successful?
Select the two correct answers.
(a)
WOW! eBook
www.wowebook.org

Click here to view code image
Current directory: /top/wrk
Command: javac -cp .:pkg A.java

(b)
Click here to view code image
Current directory: /top/wrk
Command: javac -cp . pkg/A.java

(c)
Current directory: /top/wrk
Command: javac -cp pkg A.java

(d)
Click here to view code image
Current directory: /top/wrk
Command: javac -cp .:pkg pkg/A.java

(e)
Click here to view code image
Current directory: /top/wrk/pkg
Command: javac A.java

(f)
Click here to view code image
Current directory: /top/wrk/pkg
Command: javac -cp . A.java

4.7 Given the following directory structure:
Click here to view code image
/proj
|– src
|
|– A.java
|
|
|– bin
|– top
|– sub
|– A.class

Assume that the current directory is /proj/src. Which class path specifications
will find the file A.class of the class top.sub.A declared in the file
/proj/src/A.java?
Select the two correct answers.
(a) -cp /proj/bin/top
(b) -cp /proj/bin/top/sub
(c) -cp /proj/bin/top/sub/A.class
(d) -cp .:../bin
(e) -cp /proj
WOW! eBook
www.wowebook.org

(f) -cp /proj/bin

4.4 Scope Rules
Java provides explicit accessibility modifiers to control the accessibility of members in a
class by external clients (§4.7, p. 123), but in two areas access is governed by specific
scope rules:
• Class scope for members: how member declarations are accessed within the class.
• Block scope for local variables: how local variable declarations are accessed within
a block.

Class Scope for Members
Class scope concerns accessing members (including inherited ones) from code within a
class. Table 4.1 gives an overview of how static and non-static code in a class can access
members of the class, including those that are inherited. Table 4.1 assumes the following
declarations:
Click here to view code image
class SuperName {
int instanceVarInSuper;
static int staticVarInSuper;
void instanceMethodInSuper()
{ /* … */ }
static void staticMethodInSuper() { /* … */ }
// …
}
class ClassName extends SuperName {
int instanceVar;
static int staticVar;
void instanceMethod()
{ /* … */ }
static void staticMethod() { /* … */ }
// …
}

WOW! eBook
www.wowebook.org

Table 4.1

Accessing Members within a Class

The golden rule is that static code can only access other static members by their simple
names. Static code is not executed in the context of an object, so the references this and
super are not available. An object has knowledge of its class, so static members are
always accessible in a non-static context.
Note that using the class name to access static members within the class is no different
from how external clients access these static members.
The following factors can all influence the scope of a member declaration:
• Shadowing of a field declaration, either by local variables (§4.4, p. 117) or by
declarations in the subclass (§7.3, p. 275)
• Overriding an instance method from a superclass (§7.2, p. 268)
• Hiding a static method declared in a superclass (§7.3, p. 275)
WOW! eBook
www.wowebook.org

Within a class, references of the class can be declared and used to access all members in
the class, regardless of their accessibility modifiers. In Example 4.7, the method
duplicateLight at (1) in the class Light has the parameter oldLight and the
local variable newLight that are references of the class Light. Even though the fields
of the class are private, they are accessible through the two references (oldLight
and newLight) in the method duplicateLight() as shown at (2), (3), and (4).
Example 4.7

Class Scope

Click here to view code image
class Light {
// Instance variables:
private int
noOfWatts;
private boolean indicator;
private String location;

// Wattage
// On or off
// Placement

// Instance methods:
public void switchOn() { indicator = true; }
public void switchOff() { indicator = false; }
public boolean isOn()
{ return indicator; }
public static Light duplicateLight(Light oldLight) {
Light newLight = new Light();
newLight.noOfWatts = oldLight.noOfWatts;
newLight.indicator = oldLight.indicator;
newLight.location = oldLight.location;
return newLight;
}

// (1)
// (2)
// (3)
// (4)

}

Block Scope for Local Variables
Declarations and statements can be grouped into a block using braces, {}. Blocks can be
nested, and scope rules apply to local variable declarations in such blocks. A local
declaration can appear anywhere in a block. The general rule is that a variable declared in
a block is in scope inside the block in which it is declared, but it is not accessible outside
of this block. It is not possible to redeclare a variable if a local variable of the same name
is already declared in the current scope.
Local variables of a method include the formal parameters of the method and variables
that are declared in the method body. The local variables in a method are created each time
the method is invoked, and are therefore distinct from local variables in other invocations
of the same method that might be executing (§6.5, p. 230).
Figure 4.5 illustrates block scope (also known as lexical scope) for local variables. A
method body is a block. Parameters cannot be redeclared in the method body, as shown at
(1) in Block 1.

WOW! eBook
www.wowebook.org

Figure 4.5

Block Scope

A local variable—already declared in an enclosing block and, therefore, visible in a nested
block—cannot be redeclared in the nested block. These cases are shown at (3), (5), and
(6).
A local variable in a block can be redeclared in another block if the blocks are disjoint—
that is, they do not overlap. This is the case for variable i at (2) in Block 3 and at (4) in
Block 4, as these two blocks are disjoint.
The scope of a local variable declaration begins from where it is declared in the block and
ends where this block terminates. The scope of the loop variable index is the entire
Block 2. Even though Block 2 is nested in Block 1, the declaration of the variable index
at (7) in Block 1 is valid. The scope of the variable index at (7) spans from its
declaration to the end of Block 1, and it does not overlap with that of the loop variable
index in Block 2.

4.5 Accessibility Modifiers for Top-Level Type Declarations
The accessibility modifier public can be used to declare top-level types (that is, classes,
enums, and interfaces) in a package to be accessible from everywhere, both inside their
own package and inside other packages. If the accessibility modifier is omitted, they will
be accessible only in their own package and not in any other packages or subpackages.
This is called package or default accessibility.
Example 4.8

Accessibility Modifiers for Classes and Interfaces

Click here to view code image
WOW! eBook
www.wowebook.org

// File: Clown.java
package wizard.pandorasbox;

// Package declaration

import wizard.pandorasbox.artifacts.Ailment; // Importing class Ailment
public class Clown implements Magic {
// (1)
LovePotion tlc;
// Class in same package
Ailment problem;
// Simple class name
Clown() {
tlc = new LovePotion(“passion”);
problem = new Ailment(“flu”);
// Simple class name
}
@Override public void levitate() {
// (2)
System.out.println(“Levitating”);
}
public void mixPotion() { System.out.println(“Mixing ” + tlc); }
public void healAilment() { System.out.println(“Healing ” + problem); }
public static void main(String[] args) {
Clown joker = new Clown();
joker.levitate();
joker.mixPotion();
joker.healAilment();
}
}
interface Magic { void levitate(); }

// (3)

// File: LovePotion.java
package wizard.pandorasbox;

// Package declaration

public class LovePotion {
// (4) Accessible outside
package
String potionName;
public LovePotion(String name) { potionName = name; }
public String toString() { return potionName; }
}
// File: Ailment.java
package wizard.pandorasbox.artifacts;

// Package declaration

public class Ailment {
// Accessible outside package
String ailmentName;
public Ailment(String name) { ailmentName = name; }
public String toString() { return ailmentName; }
}
// File: Baldness.java
package wizard.spells;

// Package declaration

import wizard.pandorasbox.*;
import wizard.pandorasbox.artifacts.*;

// Redundant
// Import of subpackage

public class Baldness extends Ailment {
wizard.pandorasbox.LovePotion tlcOne;
LovePotion tlcTwo;
Baldness(String name) {
super(name);
tlcOne = new wizard.pandorasbox.
LovePotion(“romance”);
tlcTwo = new LovePotion();

// Simple name for Ailment
// Fully qualified name
// Class in same package

// Fully qualified name
// Class in same package

WOW! eBook
www.wowebook.org

}
}
class LovePotion /* implements Magic */ {
// @Override public void levitate() {}
}

// (5) Magic is not accessible
// (6) Cannot override method

Compiling and running the program from the current directory gives the following results:
Click here to view code image
>javac -d . Clown.java LovePotion.java Ailment.java Baldness.java
>java wizard.pandorasbox.Clown
Levitating
Mixing passion
Healing flu

In Example 4.8, the class Clown at (1) and the interface Magic at (3) are placed in a
package called wizard.pandorasbox. The public class Clown is accessible from
everywhere. The Magic interface has default accessibility, and can be accessed only
within the package wizard.pandorasbox. It is not accessible from other packages,
not even from subpackages.
The class LovePotion at (4) is also placed in the package called
wizard.pandorasbox. The class has public accessibility and, therefore, is
accessible from other packages. The two files Clown.java and LovePotion.java
demonstrate how several compilation units can be used to group classes in the same
package.
In the file Clown.java, the class Clown at (1) implements the interface Magic at (3)
from the same package. We have used the annotation @Override in front of the
declaration of the levitate() method at (2) so that the compiler can aid in checking
that this method is declared correctly as required by the interface Magic.
In the file Baldness.java, the class LovePotion at (5) wishes to implement the
interface Magic at (3) from the package wizard.pandorasbox, but cannot do so,
although the source file imports from this package. The reason is that the interface Magic
has default accessibility and can, therefore, be accessed only within the package
wizard.pandorasbox. The method levitate() of the Magic interface therefore
cannot be overridden in class LovePotion at (6).
Just because a reference type is accessible does not necessarily mean that members of the
type are also accessible. Member accessibility is governed separately from type
accessibility, as explained in §4.7, p. 123. Table 4.2 gives a summary of accessibility
modifiers for top-level types.

WOW! eBook
www.wowebook.org

Table 4.2

Summary of Accessibility Modifiers for Top-Level Types

4.6 Non-Accessibility Modifiers for Classes
The non-accessibility modifiers abstract and final can be applied to top-level
classes.

Classes
A class can be declared with the keyword abstract to indicate that it cannot be
instantiated. A class might choose to do this if the abstraction it represents is so general
that it needs to be specialized to be of practical use. The class Vehicle might be
specified as abstract to represent the general abstraction of a vehicle, as creating
instances of the class would not make much sense. Creating instances of non-abstract
subclasses, like Car and Bus, would make more sense, as this would make the
abstraction more concrete.
Any normal class (that is, a class declared with the keyword class) can be declared as
abstract. However, if such a class has one or more abstract methods (§4.8, p. 136),
it must be declared as abstract. Obviously, such classes cannot be instantiated, as their
implementation might be only partial. A class might choose this strategy to dictate certain
behavior, but allow its subclasses the freedom to provide the relevant implementation. In
other words, subclasses of the abstract class have to take a stand and provide
implementations of any inherited abstract methods before instances can be created. A
subclass that does not provide an implementation of its inherited abstract methods
must also be declared as abstract or the code will not compile.
In Example 4.9, the declaration of the abstract class Light has an abstract
method named kwhPrice at (1). This forces its concrete (i.e., non-abstract) subclasses to
provide an implementation for this method. Such a class provides implementations of all
its methods. The concrete subclass TubeLight provides an implementation for the
method kwhPrice() at (2). The class Factory creates an instance of the class
TubeLight at (3). References of an abstract class can be declared, as shown at (4),
but an abstract class cannot be instantiated, as shown at (5). References of an
abstract class can refer to objects of the subclasses, as shown at (6).

WOW! eBook
www.wowebook.org

Example 4.9

Abstract Classes

Click here to view code image
abstract class Light {
// Fields:
int
noOfWatts;
boolean indicator;
String location;

// Wattage
// On or off
// Placement

// Instance methods:
public void switchOn() { indicator = true; }
public void switchOff() { indicator = false; }
public boolean isOn()
{ return indicator; }
// Abstract instance method
public abstract double kwhPrice();

// (1) No method body
}
//______________________________________________________________________________
class TubeLight extends Light {
// Field
int tubeLength;
// Implementation of inherited abstract method.
@Override public double kwhPrice() { return 2.75; } // (2)
}
//______________________________________________________________________________
public class Factory {
public static void main(String[] args) {
TubeLight cellarLight = new TubeLight();
// (3) OK
Light nightLight;
// (4) OK
// Light tableLight = new Light();
// (5) Compile-time
error
nightLight = new TubeLight();
// (6) OK
System.out.println(“KWH price: $” + nightLight.kwhPrice());
}
}

Output from the program:
KWH price: $2.75

Classes
A class can be declared as final to indicate that it cannot be extended; that is, one
cannot declare subclasses of a final class. This implies that one cannot override any
methods declared in such a class. In other words, the class behavior cannot be changed by
extending the class. A final class marks the lower boundary of its implementation
inheritance hier-archy (§7.1, p. 264). Only a concrete class can be declared as final.
A final class must be complete, whereas an abstract class is considered incomplete.
Classes, therefore, cannot be both final and abstract at the same time. Interfaces are
inherently abstract, as they can specify methods that are abstract, and therefore cannot
be declared as final. A final class and an interface represent two extremes when it
comes to providing an implementation. An abstract class represents a compromise
between these two extremes. Table 4.3 provides a summary of non-accessibility modifiers
for classes.
WOW! eBook
www.wowebook.org

Table 4.3

Summary of Non-Accessibility Modifiers for Classes

The Java SE platform API includes many final classes—for example, the
java.lang.String class and the wrapper classes for primitive values.
If it is decided that the class TubeLight in Example 4.9 may not be extended, it can be
declared as final:
Click here to view code image
final class TubeLight extends Light {
// …
}

Discussion of final methods, fields, and local variables can be found in §4.8, p. 133.

Review Questions
4.8 Given the following class, which of these alternatives are valid ways of referring to
the class from outside of the package net.basemaster?
package net.basemaster;
public class Base {
// …
}

Select the two correct answers.
(a) By simply referring to the class as Base
(b) By simply referring to the class as basemaster.Base
(c) By simply referring to the class as net.basemaster.Base
(d) By importing with net.basemaster.*, and referring to the class as Base
(e) By importing with net.*, and referring to the class as basemaster.Base
4.9 Which one of the following class declarations is a valid declaration of a class that
cannot be instantiated?
Select the one correct answer.
(a) class Ghost

{ abstract void haunt(); }

(b) abstract class Ghost { void haunt(); }
WOW! eBook
www.wowebook.org

(c) abstract class Ghost { void haunt() {}; }
(d) abstract Ghost

{ abstract void haunt(); }

(e) abstract class Ghost { abstract haunt(); }
4.10 Which one of the following class declarations is a valid declaration of a class that
cannot be extended?
Select the one correct answer.
(a) class Link { }
(b) abstract class Link { }
(c) native class Link { }
(d) final class Link { }
(e) abstract final class Link { }

4.7 Member Accessibility Modifiers
By specifying member accessibility modifiers, a class can control which information is
accessible to clients (that is, other classes). These modifiers help a class to define a
contract so that clients know exactly which services are offered by the class.
The accessibility of members can be one of the following:
public
protected
Default accessibility (also known as package accessibility), meaning that no
accessibility modifier is specified
private
In the following discussion of accessibility modifiers for members of a class, keep in mind
that the member accessibility modifier has meaning only if the class (or one of its
subclasses) is accessible to the client. Also, note that only one accessibility modifier can
be specified for a member.
The discussion in this section applies to both instance and static members of top-level
classes. It applies equally to constructors as well.
In UML notation, the prefixes +, #, and -, when applied to a member name, indicate
public, protected, and private member accessibility, respectively. No prefix
indicates default or package accessibility.

Members
Public accessibility is the least restrictive of all the accessibility modifiers. A public
member is accessible from anywhere, both in the package containing its class and in other
packages where this class is visible.
WOW! eBook
www.wowebook.org

Example 4.10 contains two source files, shown at (1) and (6). The package hierarchy
defined by the source files is depicted in Figure 4.6, showing the two packages,
packageA and packageB, containing their respective classes. The classes in
packageB use classes from packageA. The class SuperclassA in packageA has
two subclasses: SubclassA in packageA and SubclassB in packageB.

Figure 4.6

Public Accessibility for Members

WOW! eBook
www.wowebook.org

Example 4.10

Public Accessibility of Members

Click here to view code image
// File: SuperclassA.java
package packageA;

(1)

public class SuperclassA {
public int superclassVarA;
public void superclassMethodA() {/*…*/}
}
class SubclassA extends SuperclassA {
void subclassMethodA() { superclassVarA = 10; }
}
class AnyClassA {
SuperclassA obj = new SuperclassA();
void anyClassMethodA() {
obj.superclassMethodA();
}
}

// File: SubclassB.java
package packageB;
import packageA.*;

// (2)
// (3)

// (4) OK

// (5) OK

(6)

public class SubclassB extends SuperclassA {
void subclassMethodB() { superclassMethodA(); }
}
class AnyClassB {
SuperclassA obj = new SuperclassA();
void anyClassMethodB() {
obj.superclassVarA = 20;
}
}

// (7) OK

// (8) OK

Accessibility is illustrated in Example 4.10 by the accessibility modifiers for the field
superclassVarA and the method superclassMethodA() at (2) and (3),
respectively, defined in the class SuperclassA. These members are accessed from four
different clients in Example 4.10.
• Client 1: From a subclass in the same package, which accesses an inherited field
from the class SuperclassA. SubclassA is such a client, and does this at (4).
• Client 2: From a non-subclass in the same package, which invokes a method on an
instance of the SuperclassA class. AnyClassA is such a client, and does this at
(5).
• Client 3: From a subclass in another package, which invokes an inherited method
from the class SuperclassA. SubclassB is such a client, and does this at (7).
• Client 4: From a non-subclass in another package, which accesses a field in an
instance of the SuperclassA class. AnyClassB is such a client, and does this at
(8).
WOW! eBook
www.wowebook.org

In Example 4.10, the field superclassVarA and the method
superclassMethodA() have public accessibility in the SuperclassA class, and
are accessible by all four of these clients. Subclasses can access their inherited public
members by their simple names, and all clients can access public members in an instance
of the SuperclassA class. Public accessibility is depicted in Figure 4.6.

Members
A protected member is accessible in all classes in the same package, and by all subclasses
of its class in any package where this class is visible. In other words, non-subclasses in
other packages cannot access protected members from other packages. This kind of
accessibility is more restrictive than public member accessibility.
In Example 4.10, if the field superclassVarA and the method
superclassMethodA() of the class SuperclassA have protected accessibility,
they are accessible within packageA, and only accessible by subclasses in any other
packages.
Click here to view code image
public class SuperclassA {
protected int superclassVarA;
protected void superclassMethodA() {/*…*/}
}

// (2) Protected member
// (3) Protected member

Client 4 in packageB cannot access these members, as shown in Figure 4.7.

Figure 4.7

Protected Accessibility for Members

An important caveat is that a subclass in another package can access only protected
members in the superclass via references of its own type or its subtypes. The following
new declaration of SubclassB in packageB from Example 4.10 illustrates the point:
Click here to view code image
// File: SubclassB.java
package packageB;
import packageA.*;
WOW! eBook
www.wowebook.org

public class SubclassB extends SuperclassA {
SuperclassA objRefA = new SuperclassA();
void subclassMethodB(SubclassB objRefB) {
objRefB.superclassMethodA();
objRefB.superclassVarA = 5;
objRefA.superclassMethodA();
objRefA.superclassVarA = 10;
}
}

// In packageB
// (1)
//
//
//
//

(2)
(3)
(4)
(5)

OK
OK
Not OK
Not OK

The class SubclassB declares the field objRefA of type SuperclassA at (1). The
method subclassMethodB() has the formal parameter objRefB of type
SubclassB. Access is permitted to a protected member of SuperclassA in
packageA by a reference of the subclass, as shown at (2) and (3), but not by a reference
of its superclass, as shown at (4) and (5). Access to the field superclassVarA and the
call to the method superclassMethodA() occur in SubclassB. These members are
declared in SuperclassA. SubclassB is not involved in the implementation of
SuperclassA, which is the type of the reference objRefA. Hence, access to protected
members at (4) and (5) is not permitted as these are not members of an object that can be
guaranteed to be implemented by the code accessing them.
Accessibility to protected members of the superclass would also be permitted via any
reference whose type is a subclass of SubclassB. The previously mentioned restriction
helps to ensure that subclasses in packages different from their superclass can access
protected members of the superclass only in their part of the implementation inheritance
hierarchy. In other words, a protected member of a superclass is accessible in a subclass
that is in another package only if the member is inherited by an object of the subclass (or
by an object of a subclass of this subclass).

Default Accessibility for Members
When no member accessibility modifier is specified, the member is accessible only to
other classes in its own class’s package. Even if its class is visible in another (possibly
nested) package, the member is not accessible elsewhere. Default member accessibility is
more restrictive than protected member accessibility.
In Example 4.10, if the field superclassVarA and the method
superclassMethodA() are defined with no accessibility modifier, they are accessible
within packageA, but not in any other packages.
Click here to view code image
public class SuperclassA {
int superclassVarA;
accessibility
void superclassMethodA() {/*…*/}
}

// (2) Default
// (3) Default accessibility

The clients in packageB (that is, Clients 3 and 4) cannot access these members. This
situation is depicted in Figure 4.8.

WOW! eBook
www.wowebook.org

Figure 4.8

Default Accessibility for Members

Members
The private modifier is the most restrictive of all the accessibility modifiers. Private
members are not accessible from any other classes. This also applies to subclasses,
whether they are in the same package or not. Since they are not accessible by their simple
names in a subclass, they are also not inherited by the subclass. A standard design strategy
for a class is to make all fields private and provide public accessor methods for them.
Auxiliary methods are often declared as private, as they do not concern any client.
In Example 4.10, if the field superclassVarA and the method
superclassMethodA() have private accessibility, they are not accessible by any
other clients.
Click here to view code image
public class SuperclassA {
private int superclassVarA;
private void superclassMethodA() {/*…*/}
}

// (2) Private member
// (3) Private member

None of the clients in Figure 4.9 can access these members. Table 4.4 provides a summary
of accessibility modifiers for members.

WOW! eBook
www.wowebook.org

Figure 4.9

Table 4.4

Private Accessibility for Members

Summary of Accessibility Modifiers for Members

Review Questions
4.11 Given the following declaration of a class, which field is accessible from outside
the package com.corporation.project?
Click here to view code image
package com.corporation.project;
public class MyClass {
int i;
public
int j;
protected int k;
private
int l;
}

Select the one correct answer.
(a) Field i is accessible in all classes in other packages.
(b) Field j is accessible in all classes in other packages.
(c) Field k is accessible in all classes in other packages.
WOW! eBook
www.wowebook.org

(d) Field k is accessible in subclasses only in other packages.
(e) Field l is accessible in all classes in other packages.
(f) Field l is accessible in subclasses only in other packages.
4.12 How restrictive is the default accessibility compared to public, protected,
and private accessibility?
Select the one correct answer
(a) Less restrictive than public
(b) More restrictive than public, but less restrictive than protected
(c) More restrictive than protected, but less restrictive than private
(d) More restrictive than private
(e) Less restrictive than protected from within a package, and more restrictive
than protected from outside a package
4.13 Which statement is true about the accessibility of members?
Select the one correct answer.
(a) A private member is always accessible within the same package.
(b) A private member can be accessed only within the class of the member.
(c) A member with default accessibility can be accessed by any subclass of the
class in which it is declared.
(d) A private member cannot be accessed at all.
(e) Package/default accessibility for a member can be declared using the keyword
default.
4.14 Which lines that are marked will compile in the following code?
Click here to view code image
// File name: A.java
package packageA;
public class A {
protected int pf;
}
// File name: B.java
package packageB;
import packageA.A;
public class B extends A {
void action(A obj1, B obj2, C obj3) {
pf = 10;
// (1)
obj1.pf = 10;
// (2)
obj2.pf = 10;
// (3)
obj3.pf = 10;
// (4)
}
}
WOW! eBook
www.wowebook.org

class C extends B {
void action(A obj1, B obj2, C obj3) {
pf = 10;
// (5)
obj1.pf = 10;
// (6)
obj2.pf = 10;
// (7)
obj3.pf = 10;
// (8)
}
}
class D {
void action(A obj1, B obj2, C obj3) {
pf = 10;
// (9)
obj1.pf = 10;
// (10)
obj2.pf = 10;
// (11)
obj3.pf = 10;
// (12)
}
}

Select the five correct answers.
(a) (1)
(b) (2)
(c) (3)
(d) (4)
(e) (5)
(f) (6)
(g) (7)
(h) (8)
(i) (9)
(j) (10)
(k) (11)
(l) (12)

4.8 Non-Accessibility Modifiers for Members
The following keywords can be used to specify certain aspects of members in a type
declaration:
static
final
abstract
synchronized
native
WOW! eBook
www.wowebook.org

transient
volatile

Members
Static members belong to the class in which they are declared and are not part of any
instance of the class. The declaration of static members is prefixed by the keyword
static to distinguish them from instance members. Depending on the accessibility
modifiers of the static members in a class, clients can access these members by using the
class name or through object references of the class. The class need not be instantiated to
access its static members.
Static variables (also called class variables) exist only in the class in which they are
defined. They are not instantiated when an instance of the class is created. In other words,
the values of these variables are not a part of the state of any object. When the class is
loaded, static variables are initialized to their default values if no explicit initialization
expression is specified.
Static methods are also known as class methods. A static method in a class can directly
access other static members in the class. It cannot access instance (i.e., non-static)
members of the class directly, as there is no notion of an object associated with a static
method.
A typical static method might perform some task on behalf of the whole class or for
objects of the class. In Example 4.11, the static variable counter keeps track of the
number of instances of the Light class that have been created. The example shows that
the static method writeCount() can access static members directly, as shown at (2),
but not non-static members, as shown at (3). The static variable counter at (1) will be
initialized to the default value 0 when the class is loaded at runtime. The main() method
at (4) in the class Warehouse shows how static members of the class Light can be
accessed using the class name and via object references of the type Light.
A summary of how static members are accessed in static and non-static code is given in
Table 4.1, p. 115.

WOW! eBook
www.wowebook.org

Example 4.11

Accessing Static Members

Click here to view code image
class Light {
// Fields:
int
noOfWatts;
boolean indicator;
String location;
// Static variable
static int counter;

// Wattage
// On or off
// Placement

// Number of Light objects created

(1)

// Non-zero argument constructor
Light(int noOfWatts, boolean indicator, String location) {
this.noOfWatts = noOfWatts;
this.indicator = indicator;
this.location = location;
++counter;
// Increment counter.
}
// Static method
public static void writeCount() {
System.out.println(“Number of lights: ” + counter);
// Compile-time error. Field noOfWatts is not accessible:
// System.out.println(“Number of Watts: ” + noOfWatts);
}

// (2)
// (3)

}
//______________________________________________________________________________
public class Warehouse {
public static void main(String[] args) {
// (4)
Light.writeCount();

// Invoked using class

name
Light light1 = new Light(100, true, “basement”); // Create an object
System.out.println(
“Value of counter: ” + Light.counter
// Accessed via class
name
);
Light light2 = new Light(200, false, “garage”);
light2.writeCount();
reference
Light light3 = new Light(300, true, “kitchen”);
System.out.println(
“Value of counter: ” + light3.counter
reference
);
}
}

Output from the program:
Number of lights:
Value of counter:
Number of lights:
Value of counter:

0
1
2
3

WOW! eBook
www.wowebook.org

// Create another object
// Invoked using
// Create another object
// Accessed via

Members
A final variable is a constant despite being called a variable. Its value cannot be
changed once it has been initialized. Instance and static variables can be declared as
final. Note that the keyword final can also be applied to local variables, including
formal parameters of a method. Declaring a variable as final has the following
implications:
• A final variable of a primitive data type cannot change its value once it has been
initialized.
• A final variable of a reference type cannot change its reference value once it has
been initialized. This effectively means that a final reference will always refer to
the same object. However, the keyword final has no bearing on whether the state
of the object denoted by the reference can be changed.
• After the constructor exits, the final fields of a object are all guaranteed to be
initialized. The compiler ensures that the class provides the appropriate code to
initialize the final fields.
A final variable must be explicitly initialized only once with an initializer expression,
either in its declaration or in an initializer block (§9.7, p. 399). A final instance variable
can also be initialized in a constructor.
Note that a final local variable need not be initialized in its declaration, but it must be
initialized in the code once before it is used. These variables are also known as blank final
variables. For a discussion of final parameters, see §3.5, p. 80.
A final method in a class is a concrete method (that is, has an implementation) and
cannot be overridden in any subclass (§7.2, p. 268).
Variables declared as final ensure that values cannot be changed and methods declared
as final ensure that behavior cannot be changed. Classes declared as final are
discussed in §4.6, p. 122.
The compiler may be able to perform code optimizations for final members, because
certain assumptions can be made about such members.
Static final variables are commonly used to define manifest constants (also called named
constants)—for example, Integer.MAX_VALUE, which is the maximum int value.
Variables defined in an interface are implicitly final (§7.6, p. 290).
In Example 4.12, the class Light defines two public static final variables at
(1) and (2). The public static final variable KWH_PRICE is initialized in the
declaration at (1), and the public static final variable MANUFACTURER is
initialized in the static initializer block at (3). An attempt to change the value of the
public static final variable KWH_PRICE at (9) results in a compile-time error.
The class Light also defines two final instance variables at (4) and (5). The final
instance variable color is initialized in the instance initializer block at (6), and the
WOW! eBook
www.wowebook.org

final instance variable energyRating is initialized in the constructor at (7).
The class Light also defines a final method at (8). The subclass TubeLight
attempts to override the final method setWatts() from the superclass Light at
(10), which is not permitted.
The class Warehouse also defines a final local reference workLight at (11). The
state of the object denoted by the reference workLight is changed at (12), but its
reference value cannot be changed as attempted at (13). Another final local reference
alarmLight is declared at (14), but it is not initialized. The compiler reports an error
when an attempt is made to use this reference at (15).
Example 4.12

Using final Modifier

Click here to view code image
class Light {
// Static final variables
public static final double KWH_PRICE = 3.25;
public static final String MANUFACTURER;
static {
MANUFACTURER = “Ozam”;
}

// Static initializer block
// (3) Initializes (2)

// Instance variables
int noOfWatts;
final String color;
final String energyRating;

// (4)
// (5)

{
block
color = “off white”;
}

// Instance initializer
// (6) Initializes (4)

// Constructor
Light() {
energyRating = “A++”;
}

// (7) Initializes (5)

// Final instance method
final public void setWatts(int watt) {
noOfWatts = watt;
}
public void setKWH() {
// KWH_PRICE = 4.10;
}

// (1)
// (2)

(8)

// (9) Not OK. Cannot be changed.

}
//______________________________________________________________________________
class TubeLight extends Light {
// Final method in superclass cannot be overridden.
// This method will not compile.
/*
@Override
public void setWatts(int watt) {
// (10) Attempt to override.
noOfWatts = 2*watt;
}
*/
WOW! eBook
www.wowebook.org

}
//______________________________________________________________________________
public class Warehouse {
public static void main(String[] args) {
final Light workLight = new Light(); // (11) Final local variable.
workLight.setWatts(100);
// (12) OK. Changing object state.
// workLight = new Light();
// (13) Not OK. Changing final
reference.
final Light alarmLight;
alarmLight.setWatts(200);

//

// (14) Not initialized.
// (15) Not OK.

System.out.println(“KWH_PRICE:
System.out.println(“MANUFACTURER:
System.out.println(“noOfWatts:
System.out.println(“color:
System.out.println(“energyRating:

”
”
”
”
”

+
+
+
+
+

Light.KWH_PRICE);
Light.MANUFACTURER);
workLight.noOfWatts);
workLight.color);
workLight.energyRating);

}
}

Output from the program:
KWH_PRICE:
MANUFACTURER:
noOfWatts:
color:
energyRating:

3.25
Ozam
100
off white
A++

Methods
An abstract method in an abstract class has the following syntax:
Click here to view code image

accessibility_modifier abstract return_type method_name
(formal_parameter_list)
throws_clause;
An abstract method does not have an implementation; that is, no method body is defined
for an abstract method, and only the method header is provided in the class declaration.
The keyword abstract is mandatory in the header of an abstract method declared in a
class. Its class is then incomplete and must be explicitly declared as abstract (§4.6, p.
120). Subclasses of an abstract class must then provide the method implementation;
otherwise, they must also be declared as abstract. The accessibility of an abstract
method declared in a top-level class cannot be private, as subclasses would not be able
to override the method and provide an implementation. See §4.6, where Example 4.9 also
illustrates the use of abstract methods.
Only an instance method can be declared as abstract. Since static methods cannot be
overridden, declaring an abstract static method makes no sense, and the compiler will
report an error. A final method cannot be abstract (i.e., cannot be incomplete), and
vice versa. The keyword abstract can be specified only in combination with the
public or protected accessibility modifier.
Abstract methods specified in a top-level interface are implicitly abstract, and the
WOW! eBook
www.wowebook.org

keyword abstract is seldom specified in their method headers. These methods can
have only public accessibility. See §7.6, p. 291, for a discussion of abstract methods in
top-level interfaces.

Methods
A thread is an independent path of execution in a program. Several threads can be
executing in a program. They might try to execute several methods on the same object
simultaneously. Methods can be declared as synchronized if it is desired that only one
thread at a time be able to execute a method of the object. Their execution is then mutually
exclusive among all threads. At any given time, at most one thread can be executing a
synchronized method on an object. This discussion also applies to static
synchronized methods of a class.
In Example 4.13, both the push() method, declared at (1), and the pop() method,
declared at (2), are synchronized in the class StackImpl. Only one thread at a time
can execute a synchronized method in an object of the class StackImpl.
Consequently, it is not possible for the state of an object of the class StackImpl to be
corrupted, for example, while one thread is pushing an element and another is attempting
to pop the stack.
Example 4.13

Synchronized Methods

Click here to view code image
class StackImpl {
// Non-generic partial implementation
private Object[] stackArray;
private int topOfStack;
// …
synchronized public void push(Object elem) { // (1)
stackArray[++topOfStack] = elem;
}
synchronized public Object pop() {
Object obj = stackArray[topOfStack];
stackArray[topOfStack] = null;
topOfStack—;
return obj;
}

// (2)

// Other methods, etc.
public Object peek() { return stackArray[topOfStack]; }
}

WOW! eBook
www.wowebook.org

Methods
Native methods are methods whose implementation is not defined in Java but rather in
another programming language, such as C or C++. Such a method can be declared as a
member in a Java class declaration. Since its implementation appears elsewhere, only the
method header is specified in the class declaration. The keyword native is mandatory in
the method header. A native method can also specify checked exceptions in a throws
clause (§6.9, p. 251), but the compiler cannot check them, since the method is not
implemented in Java.
The Java Native Interface (JNI) is a special API that allows Java methods to invoke native
functions implemented in C.
In the following example, a native method in the class Native is declared at (2). The
class also uses a static initializer block to load the native library when the class is loaded.
Clients of the Native class can call the native method like any another method, as at
(3).
Click here to view code image
class Native {
/*
* The static block ensures that the native method library
* is loaded before the native method is called.
*/
static {
System.loadLibrary(“NativeMethodLib”); // (1) Load native library.
}
native void nativeMethod();
// …

// (2) Native method header.

}
class Client {
//…
public static void main(String[] args) {
Native trueNative = new Native();
trueNative.nativeMethod();
}
//…
}

// (3) Native method call.

Fields
Often it is desirable to save the state of an object—for example, on a file. Such objects are
said to be persistent. In Java, the state of an object can be stored using serialization.
Serialization transforms objects into an output format that is conducive for storing objects.
Objects can later be retrieved in the same state as when they were serialized, meaning that
all fields included in the serialization will have the same values as at the time of
serialization.
Sometimes the value of a field in an object should not be saved, in which case the field
can be specified as transient in the class declaration. This designation implies that its
value should not be saved when objects of the class are written to persistent storage. In the
WOW! eBook
www.wowebook.org

following example, the field currentTemperature is declared as transient at (1),
because the current temperature is most likely to have changed when the object is restored
at a later date. However, the value of the field mass, declared at (2), is likely to remain
unchanged. When objects of the class Experiment are serialized, the value of the field
currentTemperature will not be saved, but that of the field mass will be, as part of
the state of the serialized object.
Click here to view code image
class Experiment implements Serializable {
// …
// The value of currentTemperature will not persist.
transient int currentTemperature;
// (1) Transient value.
double mass;

// (2) Persistent value.

}

Specifying the transient modifier for static variables is redundant and, therefore,
discouraged. Static variables are not part of the persistent state of a serialized object.

Fields
During execution, compiled code might cache the values of fields for efficiency reasons.
Since multiple threads can access the same field, it is vital that caching is not allowed to
cause inconsistencies when reading and writing the value in the field. The volatile
modifier can be used to inform the compiler that it should not attempt to perform
optimizations on the field, which could cause unpredictable results when the field is
accessed by multiple threads.
In the simple example that follows, the value of the field clockReading might be
changed unexpectedly by another thread while one thread is performing a task that
involves always using the current value of the field clockReading. Declaring the field
as volatile ensures that a write operation will always be performed on the master field
variable, and a read operation will always return the correct current value.
Click here to view code image
class VitalControl {
// …
volatile long clockReading;
// Two successive reads might give different results.
}

Table 4.5 provides a summary of non-accessibility modifiers for members.

WOW! eBook
www.wowebook.org

Table 4.5

Summary of Non-Accessibility Modifiers for Members

Review Questions
4.15 Which statements about the use of modifiers are true?
Select the two correct answers.
(a) If no accessibility modifier (public, protected, or private) is specified
for a member declaration, the member is accessible only by classes in the
package of its class and by subclasses of its class in any package.
(b) You cannot specify accessibility of local variables. They are accessible only
within the block in which they are declared.
(c) Subclasses of a class must reside in the same package as the class they extend.
(d) Local variables can be declared as static.
(e) The objects themselves do not have any accessibility modifiers; only field
references do.
4.16 Given the following source code, which comment line can be uncommented
without introducing errors?
Click here to view code image
abstract class MyClass {
abstract void f();
final
void g() {}
//final
void h() {}

// (1)
WOW! eBook
www.wowebook.org

protected static int i;
private
int j;
}
final class MyOtherClass extends MyClass {
//MyOtherClass(int n) { m = n; }

// (2)

public static void main(String[] args) {
MyClass mc = new MyOtherClass();
}
void
void
//void
//void

f()
h()
k()
l()

{}
{}
{ i++; }
{ j++; }

// (3)
// (4)

int m;
}

Select the one correct answer.
(a) (1)
(b) (2)
(c) (3)
(d) (4)
4.17 Which statement is true?
Select the one correct answer.
(a) A static method can call other non-static methods in the same class by using the
this keyword.
(b) A class may contain both static and non-static variables, and both static and
non-static methods.
(c) Each object of a class has its own instance of the static variables declared in the
class.
(d) Instance methods may access local variables of static methods.
(e) All methods in a class are implicitly passed the this reference as an argument,
when invoked.
4.18 Which one of these is not a legal member declaration within a class?
Select the one correct answer.
(a) static int a;
(b) final Object[] fudge = { null };
(c) abstract int t;
(d) native void sneeze();
(e) static final private double PI =
WOW! eBook
www.wowebook.org

3.14159265358979323846;
4.19 Which statements about modifiers are true?
Select the two correct answers.
(a) Abstract classes can declare final methods.
(b) Fields can be declared as native.
(c) Non-abstract methods can be declared in abstract classes.
(d) Classes can be declared as native.
(e) Abstract classes can be declared as final.
4.20 Which statement is true?
Select the one correct answer.
(a) The values of transient fields will not be saved during serialization.
(b) Constructors can be declared as abstract.
(c) The initial state of an array object constructed with the statement int[] a =
new int[10] will depend on whether the array variable a is a local variable
or a field.
(d) A subclass of a class with an abstract method must provide an
implementation for the abstract method.
(e) Only static methods can access static members.

Chapter Summary
The following topics were covered in this chapter:
• The structure of a Java source file
• Defining, using, and deploying packages
• Class scope for members, and block scope for local variables
• Accessibility (default, public) and other modifiers (abstract, final) for
reference types
• Applicability of member accessibility (default, public, protected, private)
and other member modifiers (static, final, abstract, synchronized,
native, transient, volatile)

Programming Exercise
4.1 Design a class for a bank database. The database should support the following
operations:
Deposit a certain amount into an account
WOW! eBook
www.wowebook.org

Withdraw a certain amount from an account
Get the balance (i.e., the current amount) in an account
Transfer an amount from one account to another
The amount in the transactions is a value of type double. The accounts are
identified by instances of the class Account that is in the
package com.megabankcorp.records. The database class should be placed
in a package called com.megabankcorp.system.
The deposit, withdraw, and balance operations should not have any implementation,
but should allow subclasses to provide the implementation. The transfer operation
should use the deposit and withdraw operations to implement the transfer. It should
not be possible to alter this operation in any subclass, and only classes within the
package com.megabankcorp.system should be allowed to use this operation.
The deposit and withdraw operations should be accessible in all packages. The
balance operation should be accessible only in subclasses and classes within the
package com.megabankcorp.system.

WOW! eBook
www.wowebook.org

5. Operators and Expressions

5.1 Conversions
In this section we first discuss the different kinds of type conversions that can be applied
to values; in the next section we discuss the contexts in which these conversions are
permitted. Some type conversions must be explicitly stated in the program, while others
are performed implicitly. Some type conversions can be checked at compile time to
guarantee their validity at runtime, while others will require an extra check at runtime.

WOW! eBook
www.wowebook.org

Widening and Narrowing Primitive Conversions
For the primitive data types, the value of a narrower data type can be converted to a value
of a wider data type. This is called a widening primitive conversion. Widening conversions
from one primitive type to the next wider primitive type are summarized in Figure 5.1.
The conversions shown are transitive. For example, an int can be directly converted to a
double without first having to convert it to a long and a float.

Figure 5.1

Widening Primitive Conversions

Note that the target type of a widening primitive conversion has a wider range of values
than the source type—for example, the range of the long type subsumes the range of the
int type. In widening conversions between integral types, the source value remains
intact, with no loss of magnitude information. However, a widening conversion from an
int or a long value to a float value, or from a long value to a double value, may
result in a loss of precision. The floating-point value in the target type is then a correctly
rounded approximation of the integer value. Note that precision relates to the number of
significant bits in the value, and must not be confused with magnitude, which relates how
big a value can be represented.
Converting from a wider primitive type to a narrower primitive type is called a narrowing
primitive conversion; it can result in loss of magnitude information, and possibly in a loss
of precision as well. Any conversion that is not a widening primitive conversion according
to Figure 5.1 is a narrowing primitive conversion. The target type of a narrowing primitive
conversion has a narrower range of values than the source type—for example, the range
of the int type does not include all the values in the range of the long type.
Note that all conversions between char and the two integer types byte and short are
considered narrowing primitive conversions. The reason is that the conversions between
the unsigned type char and the signed types byte or short can result in loss of
information. These narrowing conversions are done in two steps: first converting the
source value to the int type, and then converting the int value to the target type.
Widening primitive conversions are usually done implicitly, whereas narrowing primitive
conversions usually require a cast (§5.2, p. 148). It is not illegal to use a cast for a
widening conversion. However, the compiler will flag any conversion that requires a cast
if none has been specified. Regardless of any loss of magnitude or precision, widening and
narrowing primitive conversions never result in a runtime exception.
Ample examples of widening and narrowing primitive conversions can be found in this
chapter.

WOW! eBook
www.wowebook.org

Widening and Narrowing Reference Conversions
The subtype–supertype relationship between reference types determines which
conversions are permissible between them. Conversions up the type hierarchy are called
widening reference conversions (also called upcasting). Such a conversion converts from a
subtype to a supertype:
Click here to view code image
Object obj = “Upcast me”;

// Widening: Object <–— String

Conversions down the type hierarchy represent narrowing reference conversions (also
called downcasting):
Click here to view code image
String str = (String) obj; // Narrowing requires cast: String <–— Object

A subtype is a narrower type than its supertype in the sense that it is a specialization of its
supertype. Contexts under which reference conversions can occur are discussed in §7.8, p.
311.
Widening reference conversions are usually done implicitly, whereas narrowing reference
conversions usually require a cast, as illustrated in the second declaration statement in this
subsection. The compiler will reject casts that are not legal or issue an unchecked warning
under certain circumstances if type safety cannot be guaranteed.
Widening reference conversions do not require any runtime checks and never result in an
exception during execution. This is not the case for narrowing reference conversions,
which require a runtime check and can throw a ClassCastException if the
conversion is not legal.

Boxing and Unboxing Conversions
Boxing and unboxing conversions allow interoperability between primitive values and
their representation as objects of the wrapper types (§8.3, p. 346).
A boxing conversion converts the value of a primitive type to a corresponding value of its
wrapper type. If p is a value of a primitiveType, boxing conversion converts p into a
reference r of the corresponding WrapperType, such that r.primitiveTypeValue() ==
p. In the code that follows, the int value 10 results in an object of the type Integer
implicitly being created; this object contains the int value 10. We say that the int value
10 has been boxed in an object of the wrapper type Integer. The terminology
autoboxed is also used for this conversion.
Click here to view code image
Integer iRef = 10;
System.out.println(iRef.intValue() == 10);

// Boxing: Integer <–— int
// true

An unboxing conversion converts the value of a wrapper type to a value of its
corresponding primitive type. If r is a reference of a WrapperType, an unboxing
conversion converts the reference r into r.primitiveTypeValue(), where primitiveType
is the primitive type corresponding to the WrapperType. In the next code snippet, the value
in the Integer object referenced by iRef is implicitly converted to the int type. We
WOW! eBook
www.wowebook.org

say that the wrapper object has been unboxed to its corresponding primitive type.
Click here to view code image
int i = iRef;
System.out.println(iRef.intValue() == i);

// Unboxing: int <–— Integer
// true

Note that both boxing and unboxing are done implicitly in the right context. Boxing
allows primitive values to be used where an object of their wrapper type is expected, and
unboxing allows the converse. Unboxing makes it possible to use a Boolean wrapper
object as a boolean value in a boolean expression, and to use an integral wrapper object
as an integral primitive value in an arithmetic expression. Unboxing a wrapper reference
that has the null value results in a NullPointerException. Ample examples of
boxing and unboxing can be found in this chapter and in §7.8, p. 311.

Other Conversions
We briefly mention some other conversions, and identify where they are covered in this
book.
• Identity conversions are always permitted, as they allow conversions from a type to
that same type. An identity conversion is always permitted.
Click here to view code image
int i = (int) 10;
String str = (String) “Hi”;

// int <–- int
// String <–- String

• String conversions allow a value of any other type to be converted to a String
type in the context of the string concatenation operator + (§5.8, p. 174).
• Unchecked conversions are permitted to facilitate operability between legacy and
generic code (§10.1, p. 416).

5.2 Type Conversion Contexts
Selected conversion contexts and the conversions that are applicable in these contexts are
summarized in Table 5.1. The conversions shown in each context occur implicitly, without
the program having to take any special action. For other conversion contexts, see §5.1, p.
146.

WOW! eBook
www.wowebook.org

Table 5.1

Selected Conversion Contexts and Conversion Categories

Assignment Context
Assignment conversions that can occur in an assignment context are shown in the second
column of Table 5.1. An assignment conversion converts the type of an expression to the
type of a target variable.
An expression (or its value) is assignable to the target variable, if the type of the
expression can be converted to the type of the target variable by an assignment
conversion. Equivalently, the type of the expression is assignment compatible with the
type of the target variable.
For assignment conversion involving primitive data types, see §5.6, p. 158. Note the
special case where a narrowing conversion occurs when assigning a non-long integer
constant expression:
Click here to view code image
byte b = 10;

// Narrowing conversion: byte <– int
WOW! eBook
www.wowebook.org

For assignment conversions involving reference types, see §7.8, p. 311.

Method Invocation Context
Method invocation conversions that can occur in a method invocation context are shown
in the third column of Table 5.1. Note that method invocation and assignment conversions
differ in one respect: Method invocation conversions do not include the implicit narrowing
conversion performed for non-long integral constant expressions.
Click here to view code image
// Assignment: (1) Implicit narrowing followed by (2) boxing.
Character space1 = 32;
// Character <-(2)— char <-(1)— int
// Invocation of method with signature: valueOf(char)
Character space2 = Character.valueOf(32);
// Compile-time error!
// Call signature:
valueOf(int)
Character space3 = Character.valueOf((char)32); // OK!
// Call signature:
valueOf(char)

A method invocation conversion involves converting each argument value in a method or
constructor call to the type of the corresponding formal parameter in the method or
constructor declaration.
Method invocation conversions involving parameters of primitive data types are discussed
in §3.5, p. 73, and those involving reference types are discussed in §7.8, p. 311.

Casting Context of the Unary Type Cast Operator: (type)
Java, being a strongly typed language, checks for type compatibility (i.e., it checks if a
type can substitute for another type in a given context) at compile time. However, some
checks are possible only at runtime (e.g., which type of object a reference actually denotes
during execution). In cases where an operator would have incompatible operands (e.g.,
assigning a double to an int), Java demands that a type cast be used to explicitly
indicate the type conversion. The type cast construct has the following syntax:
(type) expression
The cast operator (type) is applied to the value of the expression. At runtime, a cast
results in a new value of type, which best represents the value of the expression in the old
type. We use the term casting to mean applying the cast operator for explicit type
conversion.
However, in the context of casting, implicit casting conversions can take place. These
casting conversions are shown in the fourth column of Table 5.1. Casting conversions
include more conversion categories than the assignment or the method invocation
conversions. In the code that follows, the comments indicate the category of the
conversion that takes place because of the cast operator on the right-hand side of each
assignment—although casts are only necessary for the sake of the assignment at (1) and
(2).
Click here to view code image
WOW! eBook
www.wowebook.org

long l = (long) 10;
// Widening primitive conversion: long <– int
int i = (int) l;
// (1) Narrowing primitive conversion: int <– long
Object obj = (Object) “7Up”; // Widening ref conversion: Object <– String
String str = (String) obj;
// (2) Narrowing ref conversion: String <–
Object
Integer iRef = (Integer) i; // Boxing: Integer <– int
i = (int) iRef;
// Unboxing: int <– Integer

A casting conversion is applied to the value of the operand expression of a cast operator.
Casting can be applied to primitive values as well as references. Casting between
primitive data types and reference types is not permitted, except where boxing and
unboxing is applicable. Boolean values cannot be cast to other data values, and vice versa.
The reference literal null can be cast to any reference type.
Examples of casting between primitive data types are provided in this chapter. Casting
reference values is discussed in §7.11, p. 320.

Numeric Promotion Context
Numeric operators allow only operands of certain types. Numeric promotion results in
conversions being applied to the operands to convert them to permissible types. Numeric
promotion conversions that can occur in a numeric promotion context are shown in the
fifth column of Table 5.1. Permissible conversion categories are widening primitive
conversions and unboxing conversions. A distinction is made between unary and binary
numeric promotion.
Unary Numeric Promotion
Unary numeric promotion proceeds as follows:
• If the single operand is of type Byte, Short, Character, or Integer, it is
unboxed. If the resulting value is narrower than int, it is promoted to a value of
type int by a widening conversion.
• Otherwise, if the single operand is of type Long, Float, or Double, it is unboxed.
• Otherwise, if the single operand is of a type narrower than int, its value is
promoted to a value of type int by a widening conversion.
• Otherwise, the operand remains unchanged.
In other words, unary numeric promotion results in an operand value that is either int or
wider.
Unary numeric promotion is applied in the following expressions:
• Operand of the unary arithmetic operators + and - (§5.7, p. 163)
• Array creation expression; for example, new int[20], where the dimension
expression (in this case 20) must evaluate to an int value (§3.4, p. 59)
• Indexing array elements; for example, objArray['a'], where the index
expression (in this case 'a') must evaluate to an int value (§3.4, p. 61)

WOW! eBook
www.wowebook.org

Binary Numeric Promotion
Binary numeric promotion implicitly applies appropriate widening primitive conversions
so that a pair of operands have the widest numeric type of the two, which is always at least
int. If T is the widest numeric type of the two operands after any unboxing conversions
have been performed, the operands are promoted as follows during binary numeric
promotion:
If T is wider than int, both operands are converted to T; otherwise, both operands are
converted to int.
This means that the resulting type of the operands is at least int.
Binary numeric promotion is applied in the following expressions:
• Operands of the arithmetic operators *, /, %, +, and - (§5.7, p. 163)
• Operands of the relational operators <, <=, >, and >= (§5.11, p. 180)
• Operands of the numerical equality operators == and != (§5.12, p. 181)
• Operands of the conditional operator ? :, under certain circumstances (§5.16, p.
194)

5.3 Precedence and Associativity Rules for Operators
Precedence and associativity rules are necessary for deterministic evaluation of
expressions. The operators are summarized in Table 5.2. The majority of them are
discussed in subsequent sections in this chapter. See also the index entries for these
operators.

WOW! eBook
www.wowebook.org

Table 5.2

Operator Summary

The following remarks apply to Table 5.2:
• The operators are shown with decreasing precedence from the top of the table.
• Operators within the same row have the same precedence.
• Parentheses, ( ), can be used to override precedence and associativity.
• The unary operators, which require one operand, include the following: the postfix
increment (++) and decrement (--) operators from the first row, all the prefix
operators (+, -, ++, --, ~, !) in the second row, and the prefix operators (object
creation operator new, cast operator (type)) in the third row.
• The conditional operator (? :) is ternary—that is, it requires three operands.
• All operators not identified previously as unary or ternary are binary—that is, they
require two operands.
• All binary operators, except for the relational and assignment operators, associate
from left to right. The relational operators are nonassociative.
• Except for unary postfix increment and decrement operators, all unary operators, all
assignment operators, and the ternary conditional operator associate from right to
left.
WOW! eBook
www.wowebook.org

Depending on the context, brackets ([]), parentheses (()), colon (:) and the dot operator
(.) can also be interpreted as separators (§2.1, p. 29). See the index entries for these
separators for more details.
Precedence rules are used to determine which operator should be applied first if there are
two operators with different precedence, and these operators follow each other in the
expression. In such a case, the operator with the highest precedence is applied first.
The expression 2 + 3 * 4 is evaluated as 2 + (3 * 4) (with the result 14) since *
has higher precedence than +.
Associativity rules are used to determine which operator should be applied first if there are
two operators with the same precedence, and these operators follow each other in the
expression.
Left associativity implies grouping from left to right: The expression 7 - 4 + 2 is
interpreted as ((7 - 4) + 2), since the binary operators + and - both have same
precedence and left associativity.
Right associativity implies grouping from right to left: The expression - - 4 is
interpreted as (- (- 4)) (with the result 4), since the unary operator - has right
associativity.
The precedence and associativity rules together determine the evaluation order of the
operators.

5.4 Evaluation Order of Operands
To understand the result returned by an operator, it is important to understand the
evaluation order of its operands. In general, the operands of operators are evaluated from
left to right. The evaluation order also respects any parentheses, and the precedence and
associativity rules of operators.
Examples illustrating how the operand evaluation order influences the result returned by
an operator, can be found in §5.6 and §5.9.

Left-Hand Operand Evaluation First
The left-hand operand of a binary operator is fully evaluated before the right-hand operand
is evaluated.
The evaluation of the left-hand operand can have side effects that can influence the value
of the right-hand operand. For example, in the code
Click here to view code image
int b = 10;
System.out.println((b=3) + b);

the value printed will be 6 and not 13. The evaluation proceeds as follows:
Click here to view code image
(b=3) + b
3
+ b
3
+ 3

b is assigned the value 3
WOW! eBook
www.wowebook.org

6

If evaluation of the left-hand operand of a binary operator throws an exception (§6.5, p.
230), we cannot rely on the presumption that the right-hand operand has been evaluated.

Operand Evaluation before Operation Execution
Java guarantees that all operands of an operator are fully evaluated before the actual
operation is performed. This rule does not apply to the short-circuit conditional operators
&&, ||, and ?:.
This rule also applies to operators that throw an exception (the integer division operator /
and the integer remainder operator %). The operation is performed only if the operands
evaluate normally. Any side effects of the right-hand operand will have been effectuated
before the operator throws an exception.
Example 5.1 illustrates the evaluation order of the operands and precedence rules for
arithmetic expressions. We use the eval() method at (3) in Example 5.1 to demonstrate
integer expression evaluation. The first argument to this method is the operand value that
is returned by the method, and the second argument is a string to identify the evaluation
order.
The argument to the println() method in the statement at (1) is an integer expression
to evaluate 2 + 3 * 4. The evaluation of each operand in the expression at (1) results in a
call of the eval() method declared at (3).
Click here to view code image
out.println(eval(j++, ” + “) + eval(j++, ” * “) * eval(j, “\n”));

// (1)

The output from Example 5.1 shows that the operands were evaluated first, from left to
right, before operator execution, and that the expression was evaluated as (2 + (3 *
4)), respecting the precedence rules for arithmetic expression evaluation. Note how the
value of variable j changes successively from left to right as the first two operands are
evaluated.

WOW! eBook
www.wowebook.org

Example 5.1

Evaluation Order of Operands and Arguments

Click here to view code image
import static java.lang.System.out;
public class EvalOrder{
public static void main(String[] args){
int j = 2;
out.println(“Evaluation order of operands:”);
out.println(eval(j++, ” + “) + eval(j++, ” * “) * eval(j, “\n”));

//

(1)
int i = 1;
out.println(“Evaluation order of arguments:”);
add3(eval(i++, “, “), eval(i++, “, “), eval(i, “\n”)); // (2) Three
arguments.
}
public static int eval(int operand, String str) {
// (3)
out.print(operand + str);
// Print int operand and String str.
return operand;
// Return int operand.
}
public static void add3(int operand1, int operand2, int operand3) {
(4)
out.print(operand1 + operand2 + operand3);
}
}

//

Output from the program:
Evaluation order of operands:
2 + 3 * 4
14
Evaluation order of arguments:
1, 2, 3
6

Left-to-Right Evaluation of Argument Lists
In a method or constructor invocation, each argument expression in the argument list is
fully evaluated before any argument expression to its right.
If evaluation of an argument expression does not complete normally, we cannot presume
that any argument expression to its right has been evaluated.
We can use the add3() method at (4) in Example 5.1, which takes three arguments, to
demonstrate the order in which the arguments in a method call are evaluated. The method
call at (2)
Click here to view code image
add3(eval(i++, “, “), eval(i++, “, “), eval(i, “\n”));
arguments.

// (2) Three

results in the following output, clearly indicating that the arguments were evaluated from
left to right, before being passed to the method:
1, 2, 3
WOW! eBook
www.wowebook.org

6

Note how the value of variable i changes successively from left to right as the first two
arguments are evaluated.

5.5 Representing Integers
Integer data types in Java represent signed integer values, meaning both positive and
negative integer values. The values of char type can effectively be regarded as unsigned
16-bit integers.
Values of type byte are represented as shown in Table 5.3. A value of type byte
requires 8 bits. With 8 bits, we can represent 28 or 256 values. Java uses two’s
complement (explained later) to store signed values of integer data types. For the byte
data type, this means values are in the range –128 (i.e., –27) to +127 (i.e., 27–1), inclusive.

Table 5.3

Representing Signed byte Values Using Two’s Complement

Bits in an integral value are usually numbered from right to left, starting with the least
significant bit 0 (also called the rightmost bit). The representation of the signed types sets
WOW! eBook
www.wowebook.org

the most significant bit to 1, indicating negative values. Adding 1 to the maximum int
value 2147483647 results in the minimum value -2147483648, such that the values
wrap around for integers and no overflow or underflow is indicated.

Calculating Two’s Complement
Before we look at the two’s complement, we need to understand the one’s complement.
The one’s complement of a binary integer is computed by inverting the bits in the number.
Thus, the one’s complement of the binary number 00101001 is 11010110. The one’s
complement of a binary number N2 is denoted as ~N2. The following relations hold
between a binary integer N2, its one’s complement ~N2, and its two’s complement –N2:
–N2 = ~N2 + 1
0 = –N2 + N2
If N2 is a positive binary integer, then –N2 denotes its negative binary value, and vice
versa. The second relation states that adding a binary integer N2 to its two’s complement –
N2 equals 0.
Given a positive byte value, say 41, the binary representation of -41 can be found as
follows:

Adding a number N2 to its two’s complement –N2 gives 0, and the carry bit from the
addition of the most significant bits (after any necessary extension of the operands) is
ignored:

Subtraction between two integers is also computed as addition with two’s complement:
N2 – M2 = N2 + (–M2)
For example, the expression 4110 – 310 (with the correct result 3810) is computed as
follows:
WOW! eBook
www.wowebook.org

The previous discussion of byte values applies equally to values of other integer types:
short, int, and long. These types have their values represented by two’s complement
in 16, 32, and 64 bits, respectively.

Converting Binary Numbers to Decimals
A binary number can be converted to its equivalent decimal value by computing the
positional values of its digits. Each digit in the binary number contributes to the final
decimal value by virtue of its position, starting with position 0 (units) for the rightmost
digit in the number. The positional value of each digit is given by
digit × base position
The number 1010012 corresponds to 4110 in the decimal number system:

The same technique can be used to convert a number from any base, for example, octal
(base 8) or hexadecimal (base 16), to its equivalent representation in the decimal number
system.

Converting Decimals to Binary Numbers
To convert decimals to binaries, we reverse the process outlined previously for converting
a binary to a decimal.

The divisor used in these steps is the base of the target number system (binary, base 2).
The binary value, 1010012, is represented by the remainders, with the last remainder as
WOW! eBook
www.wowebook.org

the leftmost bit.
Analogously, we can apply this procedure for converting an octal (base 8) or hexadecimal
(base 16) number to its binary equivalent.

Relationships among Binary, Octal, and Hexadecimal Numbers
We need 3 bits to represent all the octal digits (8 = 23) and 4 bits to represent all the
hexadecimal digits (16 = 24). We can use this fact to convert among the binary, octal, and
hexadecimal systems, as shown in Figure 5.2.

Figure 5.2

Converting among Binary, Octal, and Hexadecimal Numbers

The procedure for converting an octal to a binary is shown by the arrow marked (a). We
can convert an octal number to its equivalent binary number by replacing each digit in the
octal number by its 3-bit equivalent binary value.
Analogously, we can convert a hexadecimal number to its equivalent binary number by
replacing each digit in the hexadecimal number by its 4-bit equivalent binary value, as
shown by the arrow marked (b).
To convert a binary to its octal equivalent, we reverse the procedure outlined earlier
(arrow marked (c) in Figure 5.2). The bits in the binary number are grouped into 3-bit
groups from right to left. Each such group is replaced by its equivalent octal digit.
Analogously, we can convert a binary to a hexadecimal number by replacing each 4-bit
group by its equivalent hexadecimal digit (arrow marked (d) in Figure 5.2).

5.6 The Simple Assignment Operator
The assignment statement has the following syntax:
variable = expression
which can be read as “the target, variable, gets the value of the source, expression.” The
previous value of the target variable is overwritten by the assignment operator =.
The target variable and the source expression must be assignment compatible. The target
WOW! eBook
www.wowebook.org

variable must also have been declared. Since variables can store either primitive values or
reference values, expression evaluates to either a primitive value or a reference value.

Assigning Primitive Values
The following examples illustrate assignment of primitive values:
Click here to view code image
int
j =
j =
k =

j, k;
0b10;
5;
j;

// j gets the value 2.
// j gets the value 5. Previous value is overwritten.
// k gets the value 5.

The assignment operator has the lowest precedence, so that the expression on the righthand side is evaluated before the assignment is done.
Click here to view code image
int
i =
i =
i =

i;
5;
i + 1;
20 - i * 2;

// i gets the value 5.
// i gets the value 6. + has higher precedence than =.
// i gets the value 8: (20 - (i * 2))

Assigning References
Copying reference values by assignment creates aliases, which are discussed in §1.3, p. 6.
The following example recapitulates that discussion:
Click here to view code image
Pizza pizza1 = new Pizza(“Hot&Spicy”);
Pizza pizza2 = new Pizza(“Sweet&Sour”);
pizza2 = pizza1;

The variable pizza1 is a reference to a pizza that is hot and spicy, and pizza2 is a
reference to a pizza that is sweet and sour. Assigning pizza1 to pizza2 means that
pizza2 now refers to the same pizza as pizza1, the hot and spicy one. After the
assignment, these variables are aliases and either one can be used to manipulate the hot
and spicy Pizza object.
Assigning a reference value does not create a copy of the source object denoted by the
reference variable on the right-hand side. It merely assigns the reference value of the
variable on the right-hand side to the variable on the left-hand side, so that they denote the
same object. Reference assignment also does not copy the state of the source object to any
object denoted by the reference variable on the left-hand side.
A more detailed discussion of reference assignment can be found in §7.8, p. 311.

Multiple Assignments
The assignment statement is an expression statement, which means that application of the
binary assignment operator returns the value of the expression on the right-hand side.
Click here to view code image
int j, k;
j = 10;

// j gets the value 10, which is returned
WOW! eBook
www.wowebook.org

k = j;
returned

// k gets the value of j, which is 10, and this value is

The last two assignments can be written as multiple assignments, illustrating the right
associativity of the assignment operator:
Click here to view code image
k = j = 10;

// (k = (j = 10))

Multiple assignments are equally valid with references:
Click here to view code image
Pizza pizzaOne, pizzaTwo;
pizzaOne = pizzaTwo = new Pizza(“Supreme”); // Aliases

The following example shows the effect of operand evaluation order:
Click here to view code image
int[] a = {10, 20, 30, 40, 50}; // An array of int
int index = 4;
a[index] = index = 2;
// (1)

What is the value of index, and which array element a[index] is assigned a value in
the multiple assignment statement at (1)? The evaluation proceeds as follows:
Click here to view code image
a[index] = index = 2;
a[4]
= index = 2;
a[4]
= (index = 2);
associative.
a[4]
=
2;

// index gets the value 2. = is right
// The value of a[4] is changed from 50 to 2.

The following declaration statement will not compile, as the variable v2 has not been
declared:
Click here to view code image
int v1 = v2 = 2016;

// Only v1 is declared. Compile-time error!

Type Conversions in an Assignment Context
If the target and the source have the same type in an assignment, then, obviously, the
source and the target are assignment compatible and the source value need not be
converted. Otherwise, if a widening primitive conversion is permissible, then the widening
conversion is applied implicitly; that is, the source type is converted to the target type in
an assignment context.
Click here to view code image
// Widening Primitive Conversions
int
smallOne = 1234;
long
bigOne
= 2000;
double largeOne = bigOne;
double hugeOne = (double) bigOne;

//
//
//
//

No widening necessary.
Widening: int to long.
Widening: long to double.
Cast redundant but allowed.

A widening primitive conversion can result in loss of precision. In the next example, the
precision of the least significant bits of the long value may be lost when it is converting
to a float value:
Click here to view code image
WOW! eBook
www.wowebook.org

long bigInteger = 98765432112345678L;
float fpNum = bigInteger; // Widening but loss of precision: 9.8765436E16

Additionally, implicit narrowing primitive conversions on assignment can occur in cases
where all of the following conditions are fulfilled:
• The source is a constant expression of either byte, short, char, or int type.
• The target type is either byte, short, or char type.
• The value of the source is determined to be in the range of the target type at compile
time.
A constant expression is an expression that denotes either a primitive or a String literal,
and is composed of operands that can be only literals or constant variables, and operators
that can be evaluated only at compile time (for example, arithmetic and numerical
comparison operators, but not increment/decrement operators and method calls). A
constant variable is a final variable of either a primitive type or String type that is
initialized with a constant expression.
Click here to view code image
int result = 100;
// Not a constant variable. Not declared
final.
final char finalGrade = ‘A’;
// Constant variable.
System.out.printf(“%d%n%s%n%d%n%.2f%n%b%n%d%n%d%n”,
2106,
// Constant expression.
“Trust ” + “me!”,
// Constant expression.
2 + 3 * 4,
// Constant expression.
Math.PI * Math.PI * 10.0,
// Constant expression.
finalGrade == ‘A’,
// Constant expression.
Math.min(2015, 2016),
// Not constant expression. Method call.
++result
// Not constant expression. Increment
operator.
);

Here are some examples that illustrate how the conditions mentioned previously affect
narrowing primitive conversions:
Click here to view code image
// Conditions fulfilled
short s1 = 10;
//
short s2 = ‘a’;
//
char c1 = 32;
//
char c2 = (byte)35; //
cast.)
byte b1 = 40;
//
byte b2 = (short)40; //
cast.)
final int i1 = 20;
//
byte b3 = i1;
//

for implicit narrowing primitive conversions.
int value in range.
char value in range.
int value in range.
byte value in range. (int value in range, without
int value in range.
short value in range. (int value in range, without
Constant variable
final value of i1 in range.

All other narrowing primitive conversions will produce a compile-time error on
assignment and will explicitly require a cast. Here are some examples:
Click here to view code image
// Conditions not fulfilled for implicit narrowing primitive conversions.
// A cast is required.
int i2 = -20;
// i2 is not a constant variable. i2 is not final.
final int i3 = i2;
// i3 is not a constant variable, since i2 is not.
WOW! eBook
www.wowebook.org

final int i4 = 200;
final int i5;
short s3 = (short) i2;
char c3 = (char) i3;
time.
char c4 = (char) i2;
byte b4 = (byte) 128;
byte b5 = (byte) i4;
i5 = 100;
short s4 = (short) i5;
time.

//
//
//
//

i4 is a constant variable.
i5 is not a constant variable.
Not constant expression.
Final value of i3 not determinable at compile

//
//
//
//
//

Not constant expression.
int value not in range.
Value of constant variable i4 is not in range.
Initialized at runtime.
Final value of i5 not determinable at compile

Floating-point values are truncated when cast to integral values.
Click here to view code image
// The value
float huge
long giant
int
big
short small
byte tiny
char symbol

is truncated to fit the size of
= (float) 1.7976931348623157d;
= (long) 4415961481999.03D;
= (int)
giant;
= (short) big;
= (byte) small;
= (char) 112.5F;

the target type.
// double to float.
// (1) double to long.
// (2) long to int.
// (3) int to short.
// (4) short to byte.
// (5) float to char.

Table 5.4 shows how the values are truncated for assignments from (1) to (5).

Table 5.4

Examples of Truncated Values

The discussion of numeric assignment conversions also applies to numeric parameter
values at method invocation (§3.5, p. 73), except for the narrowing conversions, which
always require a cast.
The following examples illustrate boxing and unboxing in an assignment context:
Click here to view code image
Boolean
Byte
// Byte

boolRef = true;
bRef = 2;
bRef2 = 257;

// Boxing.
// Constant in range: narrowing, then boxing.
// Constant not in range. Compile-time error!

short s = 10;
// Integer
iRef1 = s;
Integer iRef3 = (int) s;

// Narrowing from int to short.
// short not assignable to Integer.
// Explicit widening with cast to int and boxing

boolean bv1 = boolRef;
byte b1 = bRef;
int
iVal = bRef;

// Unboxing.
// Unboxing.
// Unboxing and widening.

Integer iRefVal = null;
// int j = iRefVal;
if (iRef3 != null) iVal = iRef3;

// Always allowed.
// NullPointerException at runtime.
// Avoid exception at runtime.

WOW! eBook
www.wowebook.org

Review Questions
5.1 Given the following declaration:
char c = ‘A’;

What is the simplest way to convert the character value in c to an int?
Select the one correct answer.
(a) int i = c;
(b) int i = (int) c;
(c) int i = Character.getNumericValue(c);
5.2 What will be the result of compiling and running the following program?
Click here to view code image
public class Assignment {
public static void main(String[] args) {
int a, b, c;
b = 10;
a = b = c = 20;
System.out.println(a);
}
}

Select the one correct answer.
(a) The program will fail to compile, since the compiler will report that the variable
c in the multiple assignment statement a = b = c = 20; has not been
initialized.
(b) The program will fail to compile, because the multiple assignment statement a
= b = c = 20; is illegal.
(c) The code will compile, and print 10 at runtime.
(d) The code will compile, and print 20 at runtime.
5.3 What will be the result of compiling and running the following program?
Click here to view code image
public class MyClass {
public static void main(String[] args) {
String a, b, c;
c = new String(“mouse”);
a = new String(“cat”);
b = a;
a = new String(“dog”);
c = b;
System.out.println(c);
}
}

Select the one correct answer.
(a) The program will fail to compile.
WOW! eBook
www.wowebook.org

(b) The program will print mouse at runtime.
(c) The program will print cat at runtime.
(d) The program will print dog at runtime.
(e) The program will randomly print either cat or dog at runtime.

5.7 Arithmetic Operators: , , , ,
Arithmetic operators are used to construct mathematical expressions as in algebra. Their
operands are of numeric type (which includes the char type).

Arithmetic Operator Precedence and Associativity
In Table 5.5, the precedence of the operators appears in decreasing order, starting from the
top row, which has the highest precedence. Unary subtraction has higher precedence than
multiplication. The operators in the same row have the same precedence. Binary
multiplication, division, and remainder operators have the same precedence. The unary
operators have right associativity, and the binary operators have left associativity.

Table 5.5

Arithmetic Operators

Evaluation Order in Arithmetic Expressions
Java guarantees that the operands are fully evaluated from left to right before an arithmetic
binary operator is applied. If evaluation of an operand results in an error, the subsequent
operands will not be evaluated.
In the expression a + b * c, the operand a will always be fully evaluated before the
operand b, which will always be fully evaluated before the operand c. However, the
multiplication operator * will be applied before the addition operator +, respecting the
precedence rules. Note that a, b, and c are arbitrary arithmetic expressions that have been
determined to be the operands of the operators.
Example 5.1, p. 153, illustrates the evaluation order and precedence rules for arithmetic
expressions.

Range of Numeric Values
As we have seen, all numeric types have a range of valid values (§2.2, p. 37). This range is
given by the constants named MAX_VALUE and MIN_VALUE, which are defined in each
numeric wrapper type.
The arithmetic operators are overloaded, meaning that the operation of an operator varies
depending on the type of its operands. Floating-point arithmetic is performed if any
WOW! eBook
www.wowebook.org

operand of an operator is of floating-point type; otherwise, integer arithmetic is
performed.
Values that are out of range or are the results of invalid expressions are handled differently
depending on whether integer or floating-point arithmetic is performed.
Integer Arithmetic
Integer arithmetic always returns a value that is in range, except in the case of integer
division by zero and remainder by zero, which cause an ArithmeticException (see
the later discussion of the division operator / and the remainder operator %). A valid value
does not necessarily mean that the result is correct, as demonstrated by the following
examples:
Click here to view code image
int tooBig
= Integer.MAX_VALUE + 1;
Integer.MIN_VALUE.
int tooSmall = Integer.MIN_VALUE - 1;
Integer.MAX_VALUE.

// -2147483648 which is
//

2147483647 which is

These results should be values that are out of range. However, integer arithmetic wraps
round if the result is out of range; that is, the result is reduced modulo in the range of the
result type. To avoid wrapping round of out-of-range values, programs should either use
explicit checks or a wider type. If the type long is used in the earlier examples, the
results would be correct in the long range:
Click here to view code image
long notTooBig
= Integer.MAX_VALUE + 1L;
long notTooSmall = Integer.MIN_VALUE - 1L;

// 2147483648L in range.
// -2147483649L in range.

Floating-Point Arithmetic
Certain floating-point operations result in values that are out of range. Typically, adding or
multiplying two very large floating-point numbers can result in an out of-range value that
is represented by infinity (Figure 5.3). Attempting floating-point division by zero also
returns infinity. The following examples show how this value is printed as signed infinity:
Click here to view code image
System.out.println( 4.0 / 0.0);
System.out.println(-4.0 / 0.0);

// Prints: Infinity
// Prints: -Infinity

WOW! eBook
www.wowebook.org

Figure 5.3

Overflow and Underflow in Floating-Point Arithmetic

Both positive and negative infinity represent overflow to infinity; that is, the value is too
large to be represented as a double or float (Figure 5.3). Signed infinity is represented
by the named constants POSITIVE_INFINITY and NEGATIVE_INFINITY in the
wrapper classes java.lang.Float and java.lang.Double. A value can be
compared with these constants to detect overflow.
Floating-point arithmetic can also result in underflow to zero, when the value is too small
to be represented as a double or float (Figure 5.3). Underflow occurs in the following
situations:
• The result is between Double.MIN_VALUE (or Float.MIN_VALUE) and zero,
as with the result of (5.1E-324 - 4.9E-324). Underflow then returns positive
zero 0.0 (or 0.0F).
• The result is between -Double.MIN_VALUE (or -Float.MIN_VALUE) and
zero, as with the result of (-Double.MIN_VALUE * 1E-1). Underflow then
returns negative zero -0.0 (or -0.0F).
Negative zero compares equal to positive zero; in other words, (-0.0 == 0.0) is
true.
Certain operations have no mathematical result, and are represented by NaN (Not a
Number). For example, calculating the square root of -1 results in NaN. Another example
is (floating-point) dividing zero by zero:
Click here to view code image
WOW! eBook
www.wowebook.org

System.out.println(0.0 / 0.0);

// Prints: NaN

NaN is represented by the constant named NaN in the wrapper classes
java.lang.Float and java.lang.Double. Any operation involving NaN
produces NaN. Any comparison (except inequality !=) involving NaN and any other
value (including NaN) returns false. An inequality comparison of NaN with another
value (including NaN) always returns true. However, the recommended way of checking
a value for NaN is to use the static method isNaN() defined in both wrapper classes,
java.lang.Float and java.lang.Double.
Strict Floating-Point Arithmetic: strictfp
Although floating-point arithmetic in Java is defined in accordance with the IEEE-754 32bit (float) and 64-bit (double) standard formats, the language does allow JVM
implementations to use other extended formats for intermediate results. This means that
floating-point arithmetic can give different results on such JVMs, with possible loss of
precision. Such a behavior is termed non-strict, in contrast to being strict and adhering to
the standard formats.
To ensure that identical results are produced on all JVMs, the keyword strictfp can be
used to enforce strict behavior for floating-point arithmetic. The modifier strictfp can
be applied to classes, interfaces, and methods. A strictfp method ensures that all code
in the method is executed strictly. If a class or interface is declared to be strictfp, then
all code (in methods, initializers, and nested classes and interfaces) is executed strictly. If
the expression is determined to be in a strictfp construct, it is executed strictly.
Strictness, however, is not inherited by the subclasses or subinterfaces. Constant
expressions are always evaluated strictly at compile time.

Unary Arithmetic Operators: ,
The unary operators have the highest precedence of all the arithmetic operators. The unary
operator - negates the numeric value of its operand. The following example illustrates the
right associativity of the unary operators:
Click here to view code image
int value = - -10;

// (-(-10)) is 10

Notice the blank needed to separate the unary operators; otherwise, these would be
interpreted as the decrement operator -- (§5.9, p. 176), which would result in a compiletime error because a literal cannot be decremented. The unary operator + has no effect on
the evaluation of the operand value.

Multiplicative Binary Operators: , ,
Multiplication Operator: *
The multiplication operator * multiplies two numbers.
Click here to view code image
int

sameSigns

= -4

* -8;

// result:

WOW! eBook
www.wowebook.org

32

double oppositeSigns =
-32.0
int
zero
=

4

* -8.0; // Widening of int 4 to double. result:

0

* -0;

// result:

0

Division Operator: /
The division operator / is overloaded. If its operands are integral, the operation results in
integer division.
Click here to view code image
int
i1 = 4 / 5;
int
i2 = 8 / 8;
double d1 = 12 / 8;
conversion

// result: 0
// result: 1
// result: 1.0; integer division, then widening

Integer division always returns the quotient as an integer value; that is, the result is
truncated toward zero. Note that the division performed is integer division if the operands
have integral values, even if the result will be stored in a floating-point type. The integer
value is subjected to a widening conversion in the assignment context.
An ArithmeticException is thrown when integer division with zero is attempted,
meaning that integer division by zero is an illegal operation.
If any of the operands is a floating-point type, the operation performs floating-point
division, where relevant operand values undergo binary numeric promotion:
Click here to view code image
double d2 = 4.0 / 8;
double d3 = 8 / 8.0;
float d4 = 12.0F / 8;

// result: 0.5
// result: 1.0
// result: 1.5F

double result1 = 12.0 / 4.0 * 3.0;
double result2 = 12.0 * 3.0 / 4.0;

// ((12.0 / 4.0) * 3.0) which is 9.0
// ((12.0 * 3.0) / 4.0) which is 9.0

Remainder Operator: %
In mathematics, when we divide a number (the dividend) by another number (the divisor),
the result can be expressed in terms of a quotient and a remainder. For example, when 7 is
divided by 5, the quotient is 1 and the remainder is 2. The remainder operator % returns the
remainder of the division performed on the operands.
Click here to view code image
int quotient = 7 / 5;
int remainder = 7 % 5;

// Integer division operation: 1
// Integer remainder operation: 2

For integer remainder operation, where only integer operands are involved, evaluation of
the expression (x % y) always satisfies the following relation:
x == (x / y) * y + (x % y)
In other words, the right-hand side yields a value that is always equal to the value of the
dividend. The following examples show how we can calculate the remainder so that this
relation is satisfied:

WOW! eBook
www.wowebook.org

The remainder can be negative only if the dividend is negative, and the sign of the divisor
is irrelevant. A shortcut to evaluating the remainder involving negative operands is the
following: ignore the signs of the operands, calculate the remainder, and negate the
remainder if the dividend is negative.
Click here to view code image
int r0
int r1
long r2
int r3
long r4
boolean

= 7 % 7;
// 0
= 7 % 5;
// 2
= 7L % -5L;
// 2L
= -7 % 5;
// -2
= -7L % -5L;
// -2L
relation = -7L == (-7L / -5L) * -5L + r4;

// true

An ArithmeticException is thrown if the divisor evaluates to zero.
Note that the remainder operator accepts not only integral operands, but also floating-point
operands. The floating-point remainder r is defined by the relation
r == a - (b * q)
where a and b are the dividend and the divisor, respectively, and q is the integer quotient
of (a/b). The following examples illustrate a floating-point remainder operation:
Click here to view code image
double
float
double
float
double
boolean
float

dr0 = 7.0 % 7.0;
// 0.0
fr1 = 7.0F % 5.0F;
// 2.0F
dr1 = 7.0 % -5.0;
// 2.0
fr2 = -7.0F % 5.0F;
// -2.0F
dr2 = -7.0 % -5.0;
// -2.0
fpRelation = dr2 == (-7.0) - (-5.0) * (long)(-7.0 / -5.0);
fr3 = -7.0F % 0.0F;
// NaN
WOW! eBook
www.wowebook.org

// true

Additive Binary Operators: ,
The addition operator + and the subtraction operator - behave as their names imply: They
add and subtract values, respectively. The binary operator + also acts as string
concatenation if any of its operands is a string (§5.8, p. 174).
Additive operators have lower precedence than all the other arithmetic operators. Table 5.6
includes examples that show how precedence and associativity are used in arithmetic
expression evaluation.

Table 5.6

Examples of Arithmetic Expression Evaluation

Numeric Promotions in Arithmetic Expressions
Unary numeric promotion is applied to the single operand of the unary arithmetic
operators - and +. When a unary arithmetic operator is applied to an operand whose type
is narrower than int, the operand is promoted to a value of type int, with the operation
resulting in an int value. If the conditions for implicit narrowing conversion are not
fulfilled (p. 160), assigning the int result to a variable of a narrower type will require a
cast. This is demonstrated by the following example, where the byte operand b is
promoted to an int in the expression (-b):
Click here to view code image
byte b = 3;
b = (byte) -b;

// int literal in range. Narrowing conversion.
// Cast required on assignment.

Binary numeric promotion is applied to operands of binary arithmetic operators. Its
application leads to type promotion for the operands, as explained in §5.2, p. 149. The
result is of the promoted type, which is always type int or wider. For the expression at
(1) in Example 5.2, numeric promotions proceed as shown in Figure 5.4. Note the integer
division performed in evaluating the subexpression (c / s).

WOW! eBook
www.wowebook.org

Figure 5.4
Example 5.2

Numeric Promotion in Arithmetic Expressions

Numeric Promotion in Arithmetic Expressions

Click here to view code image
public class NumPromotion {
public static void main(String[] args) {
byte
b = 32;
char
c = ‘z’;
// Unicode value 122 (\u007a)
short s = 256;
int
i = 10000;
float f = 3.5F;
double d = 0.5;
double v = (d * i) + (f * -b) - (c / s);
// (1) 4888.0D
System.out.println(“Value of v: ” + v);
}
}

Output from the program:
Value of v: 4888.0

In addition to the binary numeric promotions in arithmetic expression evaluation, the
resulting value can undergo an implicit widening conversion if assigned to a variable. In
WOW! eBook
www.wowebook.org

the first two declaration statements that follow, only assignment conversions take place.
Numeric promotions take place in the evaluation of the right-hand expression in the other
declaration statements.
Click here to view code image
Byte
b = 10;
assignment.
Short s = 20;
assignment.
char
c = ‘z’;
int
i = s * b;
widening.
long
n = 20L + s;
float r = s + c;

double d = r + i;

// Constant in range: narrowing and boxing on
// Constant in range: narrowing and boxing on
// 122 (\u007a)
// Values in s and b promoted to int: unboxing,
//
//
//
//
//
//

Value in
Value in
value in
widening
Value in
widening

s promoted to long: unboxing, widening.
s is unboxed. This short value and the char
c are promoted to int, followed by implicit
conversion of int to float on assignment.
i promoted to float, followed by implicit
conversion of float to double on assignment.

Binary numeric promotion for operands of binary operators implies that each operand of a
binary operator is promoted to type int or a broader numeric type, if necessary. As with
unary operators, care must be exercised in assigning the value resulting from applying a
binary operator to operands of these types.
Click here to view code image
short h = 40;
h = h + 2;

// OK: int converted to short. Implicit narrowing.
// Error: cannot assign an int to short.

The value of the expression h + 2 is of type int. Although the result of the expression
is in the range of short, this cannot be determined at compile time. The assignment
requires a cast.
h = (short) (h + 2);

// OK

Notice that applying the cast operator (short) to the individual operands does not work:
Click here to view code image
h = (short) h + (short) 2;

// The resulting value should be cast.

Neither does the following approach, which results in a compile-time error:
Click here to view code image
h = (short) h + 2;

// The resulting value should be cast.

In this case, binary numeric promotion leads to an int value as the result of evaluating
the expression on the right-hand side and, therefore, requires an additional cast to narrow
it to a short value.

Arithmetic Compound Assignment Operators:
A compound assignment operator has the following syntax:
variable op= expression
and the following semantics:
Click here to view code image

WOW! eBook
www.wowebook.org

,

,

,

,

variable = (type) ((variable) op (expression))
The type of the variable is type and the variable is evaluated only once. Note the cast and
the parentheses implied in the semantics. Here op= can be any of the compound
assignment operators specified in Table 5.2. The compound assignment operators have the
lowest precedence of all the operators in Java, allowing the expression on the right-hand
side to be evaluated before the assignment. Table 5.7 defines the arithmetic compound
assignment operators.

Table 5.7

Arithmetic Compound Assignment Operators

The implied cast operator, (T), in the compound assignments becomes necessary when
the result must be narrowed to the target type. This is illustrated by the following
examples:
Click here to view code image
int i = 2;
i *= i + 4;
Integer iRef = 2;
iRef *= iRef + 4;
+ 4)).
byte b = 2;
b += 10;
b = b + 10;

// (1) Evaluated as i = (int) ((i) * (i + 4)).

// (2) Evaluated as iRef = (Integer) ((iRef) * (iRef

// (3) Evaluated as b = (byte) (b + 10).
// (4) Will not compile. Cast is required.

At (1) the source int value is assigned to the target int variable, and the cast operator
(int) in this case is an identity conversion (i.e., conversion from a type to the same
type). Such casts are permitted. The assignment at (2) entails unboxing to evaluate the
expression on the right-hand side, followed by boxing to assign the int value. However,
at (3), as the source value is an int value because the byte value in b is promoted to
int to carry out the addition, assigning it to a target byte variable requires an implicit
narrowing conversion. The situation at (4) with simple assignment will not compile,
because implicit narrowing conversion is not applicable.
The variable is evaluated only once in the expression, not twice, as one might infer from
the definition of the compound assignment operator. In the following assignment, a[i] is
evaluated just once:
Click here to view code image
int[] a = new int[] { 2015, 2016, 2017 };
int i = 2;
a[i] += 1;
// Evaluates as a[2] = a[2] + 1, and a[2] gets the value
WOW! eBook
www.wowebook.org

2018.

Implicit narrowing conversions are also applied to increment and decrement operators
(§5.9, p. 176).
Boolean logical compound assignment operators are covered in §5.13, p. 184.

Review Questions
5.4 Which of the following expressions will be evaluated using floating-point
arithmetic?
Select the three correct answers.
(a) 2.0 * 3.0
(b) 2 * 3
(c) 2/3 + 5/7
(d) 2.4 + 1.6
(e) 0x10 * 1L * 300.0
5.5 What is the value of the expression (1 / 2 + 3 / 2 + 0.1)?
Select the one correct answer.
(a) 1
(b) 1.1
(c) 1.6
(d) 2
(e) 2.1
5.6 What will be the result of compiling and running the following program?
Click here to view code image
public class Integers {
public static void main(String[] args) {
System.out.println(0x10 + 10 + 010 + 0b10);
}
}

Select the one correct answer.
(a) The program will not compile.
(b) When run, the program will print 28.
(c) When run, the program will print 30.
(d) When run, the program will print 34.
(e) When run, the program will print 36.
(f) When run, the program will print 10101010.
WOW! eBook
www.wowebook.org

5.7 Which of the following expressions are valid?
Select the three correct answers.
(a) (- 1 -)
(b) (+ + 1)
(c) (+-+-+-1)
(d) (—1)
(e) (1 * * 1)
(f) (- -1)
5.8 What is the value of evaluating the following expression: (- -1-3 * 10 / 51)?
Select the one correct answer.
(a) –8
(b) –6
(c) 7
(d) 8
(e) 10
(f) None of the above
5.9 Which of these assignments are valid?
Select the four correct answers.
(a) short s = 12;
(b) long l = 012;
(c) int other = (int) true;
(d) float f = -123;
(e) double d = 0x12345678;

5.8 The Binary String Concatenation Operator
The binary operator + is overloaded in the sense that the operation performed is
determined by the type of the operands. When one of the operands is a String object, a
string concatenation is performed rather than numeric addition. String concatenation
results in a newly created String object in which the characters in the string
representation of the left-hand operand precede the characters in the string representation
of the right-hand operand. It might be necessary to perform a string conversion on the
non-String operand before the string concatenation can be performed. The String
class is discussed in §8.4, p. 357.
A string conversion is performed on the non-String operand as follows:
WOW! eBook
www.wowebook.org

• For an operand of a primitive data type, its value is converted to a string
representation.
• For all reference value operands, a string representation is constructed by calling the
no-argument toString() method on the referred object. Most classes override
this method from the Object class so as to provide a more meaningful string
representation of their objects. Discussion of the toString() method can be
found in §8.2, p. 342.
• Values like true, false, and null have string representations that correspond to
their names. A reference variable with the value null also has the string
representation "null" in this context.
The operator + is left associative and has the same precedence level as the additive
operators, whether it is performed as a string concatenation or as a numeric addition.
Click here to view code image
String strVal = ”” + 2016;
String theName = ” Uranium”;
theName = ” Pure” + theName;
String trademark1 = 100 + “%” + theName;

// (1) “2016”
// (2) ” Pure Uranium”
// (3) “100% Pure Uranium”

Since the + operator is left-associative, the evaluation in (3) proceeds as follows: The int
value 100 is concatenated with the string literal "%", followed by concatenation with the
contents of the String object referred to by theName reference.
Note that using the character literal '%', instead of the string literal "%" in line (2), does
not give the same result:
Click here to view code image
String trademark2 = 100 + ‘%’ + theName;

// (4) “137 Pure Uranium”

Integer addition is performed by the first + operator: 100 + '%'; that is, (100 + 37).
Caution should be exercised because the + operator might not be applied as intended, as
shown by the following example:
Click here to view code image
System.out.println(“We can put two and two together and get ” + 2 + 2);
(5)

//

This statement prints "We can put two and two together and get 22".
String concatenation proceeds from left to right: The String literal is concatenated with
the first int literal 2, followed by concatenation with the second int literal 2. Both
occurrences of the + operator are treated as string concatenation. To convey the intended
meaning of the sentence, parentheses are necessary:
Click here to view code image
System.out.println(“We can put two and two together and get ” + (2 + 2)); //
(6)

This statement prints "We can put two and two together and get 4",
since the parentheses enforce integer addition in the expression (2 + 2) before string
concatenation is performed with the contents of the String operand.
WOW! eBook
www.wowebook.org

The following statement will print the correct result, even without the parentheses,
because the * operator has higher precedence than the + operator:
Click here to view code image
System.out.println(“2 * 2 = ” + 2 * 2);

// (7) 2 * 2 = 4

Creation of temporary String objects might be necessary to store the results of
performing successive string concatenations in a String-valued expression. For a
String-valued constant expression ((1), (5), (6) and (7) in the preceding examples), the
compiler computes such an expression at compile time, and the result is treated as a string
literal in the program. The compiler uses a string builder to avoid the overhead of
temporary String objects when applying the string concatenation operator (+) in
String-valued non-constant expressions ((2), (3) and (4) in the preceding examples), as
explained in §8.5, p. 378.

5.9 Variable Increment and Decrement Operators:

,

Variable increment (++) and decrement (--) operators come in two flavors: prefix and
postfix. These unary operators have the side effect of changing the value of the arithmetic
operand, which must evaluate to a variable. Depending on the operator used, the variable
is either incremented or decremented by 1.
These operators cannot be applied to a variable that is declared final and that has been
initialized, as the side effect would change the value in such a variable.
These operators are very useful for updating variables in loops where only the side effect
of the operator is of interest.

The Increment Operator
The prefix increment operator has the following semantics: ++i adds 1 to the value in i,
and stores the new value in i. It returns the new value as the value of the expression. It is
equivalent to the following statements:
i += 1;
result = i;
return result;

The postfix increment operator has the following semantics: j++ adds 1 to the value in j,
and stores the new value in j. It returns the original value that was in j as the value of the
expression. It is equivalent to the following statements:
result = j;
j += 1;
return result;

The Decrement Operator
The prefix decrement operator has the following semantics: --i subtracts 1 from the
value of i, and stores the new value in i. It returns the new value as the value of the
expression. It is equivalent to the following statements:
i -= 1;
WOW! eBook
www.wowebook.org

result = i;
return result;

The postfix decrement operator has the following semantics: j-- subtracts 1 from the
value of j, and stores the new value in j. It returns the original value that was in j as the
value of the expression. It is equivalent to the following statements:
result = j;
j -= 1;
return result;

This behavior of decrement and increment operators applies to any variable whose type is
a numeric primitive type or its corresponding numeric wrapper type. Necessary numeric
promotions are performed on the value 1 and the value of the variable. Before the new
value is assigned to the variable, it is subjected to any narrowing primitive conversion
and/or boxing that might be necessary.
Here are some examples that illustrate the behavior of increment and decrement operators:
Click here to view code image
// (1) Prefix order: increment/decrement operand before use.
int i = 10;
int k = ++i + —i; // ((++i) + (—i)). k gets the value 21 and i becomes 10.
—i;
// Only side effect utilized. i is 9. (expression
statement)
Integer iRef = 11; // Boxing on assignment
—iRef;
// Only side effect utilized. iRef refers
// object with the value 10. (expression
k = ++iRef + —iRef;// ((++iRef) + (—iRef)). k gets the value
// iRef refers to an Integer object with

to an Integer
statement)
21 and
the value 10.

// (2) Postfix order: increment/decrement operand after use.
long j = 10;
long n = j++ + j—; // ((j++) + (j—)). n gets the value 21L and j becomes 10L.
j++;
// Only side effect utilized. j is 11L. (expression
statement)

An increment or decrement operator, together with its operand, can be used as an
expression statement (§3.2, p. 50).
Execution of the assignment in the second declaration statement under (1) proceeds as
follows:

Execution of the expression statement --iRef; under (1) proceeds as follows:
• The value in the Integer object referred to by the reference iRef is unboxed,
resulting in the int value 11.
• The value 11 is decremented, resulting in the value 10.
• The value 10 is boxed in an Integer object, and this object’s reference value is
assigned to the reference iRef.
WOW! eBook
www.wowebook.org

• The int value 10 of the expression statement is discarded.
Expressions where variables are modified multiple times during the evaluation should be
avoided, because the order of evaluation is not always immediately apparent.
We cannot associate increment and decrement operators. Given that a is a variable, we
cannot write (++(++a)). The reason is that any operand to ++ must evaluate to a
variable, but the evaluation of (++a) results in a value.
In the next example, both binary numeric promotion and an implicit narrowing conversion
are performed to achieve the side effect of modifying the value of the operand. The int
value of the expression (++b) (that is, 11), is assigned to the int variable i. The side
effect of incrementing the value of the byte variable b requires binary numeric
promotion to perform int addition, followed by an implicit narrowing conversion of the
int value to byte to perform the assignment.
Click here to view code image
byte b = 10;
int i = ++b;

// i is 11, and so is b.

The following example illustrates applying the increment operator to a floating-point
operand. The side effect of the ++ operator is overwritten by the assignment.
Click here to view code image
double x = 4.5;
x = x + ++x;

// x gets the value 10.0.

Review Questions
5.10 Which statements are true?
Select the three correct answers.
(a) The expression (1 + 2 + "3") evaluates to the string "33".
(b) The expression ("1" + 2 + 3) evaluates to the string "15".
(c) The expression (4 + 1.0f) evaluates to the float value 5.0f.
(d) The expression (10/9) evaluates to the int value 1.
(e) The expression ('a' + 1) evaluates to the char value 'b'.
5.11 What happens when you try to compile and run the following program?
Click here to view code image
public class Prog1 {
public static void main(String[] args) {
int k = 1;
int i = ++k + k++ + + k;
// (1)
System.out.println(i);
}
}

Select the one correct answer.
WOW! eBook
www.wowebook.org

(a) The program will not compile, because of errors in the expression at (1).
(b) The program will compile and print the value 3 at runtime.
(c) The program will compile and print the value 4 at runtime.
(d) The program will compile and print the value 7 at runtime.
(e) The program will compile and print the value 8 at runtime.
5.12 Which is the first line that will cause a compile-time error in the following
program?
Click here to view code image
public class MyClass {
public static void main(String[] args) {
char c;
int i;
c = ‘a’; // (1)
i = c;
// (2)
i++;
// (3)
c = i;
// (4)
c++;
// (5)
}
}

Select the one correct answer.
(a) (1)
(b) (2)
(c) (3)
(d) (4)
(e) (5)
(f) None of the above. The compiler will not report any errors.
5.13 What is the result of compiling and running the following program?
Click here to view code image
public class Cast {
public static void main(String[] args) {
byte b = 128;
int i = b;
System.out.println(i);
}
}

Select the one correct answer.
(a) The program will not compile, because a byte value cannot be assigned to an
int variable without using a cast.
(b) The program will compile, and print 128 at runtime.
(c) The program will not compile, because the value 128 is not in the range of
values for the byte type.
WOW! eBook
www.wowebook.org

(d) The program will compile, but will throw a ClassCastException at
runtime.
(e) The program will compile, and print 255 at runtime.
5.14 What will be the result of compiling and running the following program?
Click here to view code image
public class EvaluationOrder {
public static void main(String[] args) {
int[] array = { 4, 8, 16 };
int i = 1;
array[++i] = —i;
System.out.println(array[0] + array[1] + array[2]);
}
}

Select the one correct answer.
(a) 13
(b) 14
(c) 20
(d) 21
(e) 24

5.10 Boolean Expressions
As the name implies, a boolean expression has the boolean data type and can evaluate
to only the values true or false. Boolean expressions, when used as conditionals in
control statements, allow the program flow to be controlled during execution.
Boolean expressions can be formed using relational operators (§5.11, p. 180), equality
operators (§5.12, p. 181), boolean logical operators (§5.13, p. 184), conditional operators
(§5.14, p. 186), the assignment operator (§5.6, p. 158), and the instanceof operator
(§7.11, p. 321).

5.11 Relational Operators: ,

, ,

Given that a and b represent numeric expressions, the relational (also called comparison)
operators are defined as shown in Table 5.8.

Table 5.8

Relational Operators

All relational operators are binary operators and their operands are numeric expressions.
Binary numeric promotion is applied to the operands of these operators. The evaluation
WOW! eBook
www.wowebook.org

results in a boolean value. Relational operators have precedence lower than arithmetic
operators, but higher than that of the assignment operators.
Click here to view code image
double hours = 45.5;
Double time = 18.0;
boolean overtime = hours >= 35;
int.
boolean beforeMidnight = time <
reference.
char letterA = ‘A’;
boolean order = letterA < ‘a’;
char.

// Boxing of double value.
// true. Binary numeric promotion: double <—
24.0;// true. Unboxing of value in time

// true. Binary numeric promotion: int <—

Relational operators are nonassociative. Mathematical expressions like a ≤ b ≤ c must be
written using relational and boolean logical/conditional operators.
Click here to view code image
int a = 1, b = 7, c = 10;
boolean illegal = a <= b <= c;
boolean valid2 = a <= b && b <= c;

// (1) Illegal.
// (2) OK.

Since relational operators have left associativity, the evaluation of the expression a <= b
<= c at (1) in these examples would proceed as follows: ((a <= b) <= c).
Evaluation of (a <= b) would yield a boolean value that is not permitted as an
operand of a relational operator; that is, (boolean value <= c) would be illegal.

5.12 Equality
We distinguish between primitive data equality, object reference equality, and object value
equality.
The equality operators have lower precedence than the relational operators, but higher
precedence than the assignment operators.

Primitive Data Value Equality:

,

Given that a and b represent operands of primitive data types, the primitive data value
equality operators are defined as shown in Table 5.9.

Table 5.9

Primitive Data Value Equality Operators

The equality operator == and the inequality operator != can be used to compare primitive
data values, including boolean values. Binary numeric promotion is applied to the nonboolean operands of these equality operators.
Click here to view code image
int year = 2002;
boolean isEven = year % 2 == 0;

// true.

WOW! eBook
www.wowebook.org

boolean compare = ‘1’ == 1;
applied.
boolean test
= compare == false;

// false. Binary numeric promotion
// true.

Care must be exercised when comparing floating-point numbers for equality, as an infinite
number of floating-point values can be stored only as approximations in a finite number of
bits. For example, the expression (1.0 - 2.0/3.0 == 1.0/3.0) returns false,
although mathematically the result should be true.
Analogous to the discussion for relational operators, mathematical expressions like a = b
= c must be written using relational and logical/conditional operators. Since equality
operators have left associativity, the evaluation of the expression a == b == c would
proceed as follows: ((a == b) == c). Evaluation of (a == b) would yield a
boolean value that is permitted as an operand of a data value equality operator, but
(boolean value == c) would be illegal if c had a numeric type. This problem is
illustrated in the following examples. The expression at (1) is illegal, but those at (2) and
(3) are legal.
Click here to view code image
int a, b, c;
a = b = c = 5;
boolean illegal = a == b == c;
boolean valid2 = a == b && b == c;
boolean valid3 = a == b == true;

Object Reference Equality:

// (1) Illegal.
// (2) Legal.
// (3) Legal.

,

The equality operator == and the inequality operator != can be applied to reference
variables to test whether they refer to the same object. Given that r and s are reference
variables, the reference equality operators are defined as shown in Table 5.10.

Table 5.10

Reference Equality Operators

The operands must be cast compatible: It must be possible to cast the reference value of
the one into the other’s type; otherwise, it is a compile-time error. Casting of references is
discussed in §7.8, p. 311.
Click here to view code image
Pizza pizzaA = new Pizza(“Sweet&Sour”);
Pizza pizzaB = new Pizza(“Sweet&Sour”);
Pizza pizzaC = new Pizza(“Hot&Spicy”);

// new object
// new object
// new object

String banner = “Come and get it!”;

// new object

boolean test = banner == pizzaA;
boolean test1 = pizzaA == pizzaB;
boolean test2 = pizzaA == pizzaC;

// (1) Compile-time error
// false
// false

pizzaA = pizzaB;

// Denote the same object; are
WOW! eBook
www.wowebook.org

aliases
boolean test3 = pizzaA == pizzaB;

// true

The comparison banner == pizzaA in (1) is illegal, because the String and
Pizza types are not related and therefore the reference value of one type cannot be cast
to the other type. The values of test1 and test2 are false because the three
references denote different objects, regardless of the fact that pizzaA and pizzaB are
both sweet and sour pizzas. The value of test3 is true because now both pizzaA and
pizzaB denote the same object.
The equality and inequality operators are applied to object references to check whether
two references denote the same object. The state of the objects that the references denote
is not compared. This is the same as testing whether the references are aliases, meaning
that they denote the same object.
The null literal can be assigned to any reference variable, and the reference value in a
reference variable can be compared for equality with the null literal. The comparison
can be used to avoid inadvertent use of a reference variable that does not denote any
object.
if (objRef != null) {
// … use objRef …
}

Note that only when the type of both operands is either a reference type or the null type,
do these operators test for object reference equality. Otherwise, they test for primitive data
equality (see also §8.3, p. 350). In the following code snippet, binary numeric promotion
involving unboxing is performed at (2):
Click here to view code image
Integer
boolean
boolean
boolean

iRef
b1 =
b2 =
b3 =

= 10;
iRef == null;
iRef == 10;
null == 10;

// (1) Object reference equality
// (2) Primitive data equality
// Compile-time error!

Object Value Equality
The Object class provides the method public boolean equals(Object obj),
which can be overridden (§7.2, p. 268) to give the right semantics of object value equality.
The default implementation of this method in the Object class returns true only if the
object is compared with itself, as if the equality operator == had been used to compare
aliases of an object. Consequently, if a class does not override the semantics of the
equals() method from the Object class, object value equality is the same as object
reference equality.
Certain classes in the standard API override the equals() method, such as
java.lang.String and the wrapper classes for the primitive data types. For two
String objects, value equality means they contain identical character sequences. For the
wrapper classes, value equality means that the wrapper objects have the same primitive
value and are of the same wrapper type (see also §8.3, p. 350).
Click here to view code image
WOW! eBook
www.wowebook.org

// Equality for
String movie1 =
String movie2 =
String movie3 =
boolean test0 =
boolean test1 =

String objects means identical character sequences.
new String(“The Revenge of the Exception Handler”);
new String(“High Noon at the Java Corral”);
new String(“The Revenge of the Exception Handler”);
movie1.equals(movie2);
// false.
movie1.equals(movie3);
// true.

// Equality for
Boolean flag1 =
Boolean flag2 =
boolean test2 =
boolean test3 =
value.

wrapper classes means same type and same primitive value.
true;
// Boxing.
false;
// Boxing.
flag1.equals(“true”);
// false. Not same type.
flag1.equals(!flag2);
// true. Same type and

Integer iRef = 100;
Short sRef = 100;
boolean test4 = iRef.equals(100);
value.
boolean test5 = iRef.equals(sRef);
boolean test6 = iRef.equals(3.14);

// Boxing.
// Boxing.
// true. Same type and
// false. Not same type.
// false. Not same type.

// The Pizza class does not override the equals() method, so we can use
either
// equals() method inherited from the Object class or equality operator ==.
Pizza pizza1 = new Pizza(“VeggiesDelight”);
Pizza pizza2 = new Pizza(“VeggiesDelight”);
Pizza pizza3 = new Pizza(“CheeseDelight”);
boolean test7 = pizza1.equals(pizza2);
// false.
boolean test8 = pizza1.equals(pizza3);
// false.
boolean test9 = pizza1 == pizza2;
// false.
pizza1 = pizza2;
// Creates aliases.
boolean test10 = pizza1.equals(pizza2);
// true.
boolean test11 = pizza1 == pizza2;
// true.

5.13 Boolean Logical Operators: , , ,
Boolean logical operators include the unary operator ! (logical complement) and the
binary operators & (logical AND), | (logical inclusive OR), and ^ (logical exclusive OR,
also called logical XOR). These operators can be applied to boolean or Boolean
operands, returning a boolean value. The operators &, |, and ^ can also be applied to
integral operands to perform bitwise logical operations, but are not in the scope of this
book.
Given that x and y represent boolean expressions, the boolean logical operators are defined
in Table 5.11. The precedence of the operators decreases from left to right in the table.

Table 5.11

Truth Values for Boolean Logical Operators
WOW! eBook
www.wowebook.org

These operators always evaluate both the operands, unlike their counterpart conditional
operators && and || (§5.14, p. 186). Unboxing is applied to the operand values, if
necessary. Truth values for boolean logical operators are shown in Table 5.11.

Operand Evaluation for Boolean Logical Operators
In the evaluation of boolean expressions involving boolean logical AND, XOR, and OR
operators, both the operands are evaluated. The order of operand evaluation is always
from left to right.
Click here to view code image
if (i > 0 & i++ < 10) {/*…*/} // i will be incremented, regardless of value
in i.

The binary boolean logical operators have precedence lower than the arithmetic and
relational operators, but higher precedence than the assignment, conditional AND, and OR
operators (§5.14, p. 186). This is illustrated in the following examples:
Click here to view code image
boolean b1, b2, b3 = false, b4 = false;
Boolean b5 = true;
b1 = 4 == 2 & 1 < 4;
// false, evaluated as (b1 = ((4 == 2) & (1 <
4)))
b2 = b1 | !(2.5 >= 8);
// true
b3 = b3 ^ b5;
// true, unboxing conversion on b5
b4 = b4 | b1 & b2;
// false

Here, the order of evaluation is illustrated for the last expression statement:
Click here to view code image
(b4 = (b4 | (b1
(b4 = (false |
(b4 = (false |
(b4 = (false |
(b4 = (false |
(b4 = false)
false

& b2)))
(b1 & b2)))
(false & b2)))
(false & true)))
false))

Note that b2 was evaluated although, strictly speaking, it was not necessary. This behavior
is guaranteed for boolean logical operators.

Boolean Logical Compound Assignment Operators:

,

,|

Compound assignment operators for the boolean logical operators are defined in Table
5.12. The left-hand operand must be a boolean variable, and the right-hand operand must
be a boolean expression. An identity conversion is applied implicitly on assignment.
These operators can also be applied to integral operands to perform bitwise compound
assignments, but are not covered in this book. See also the discussion on arithmetic
compound assignment operators in §5.7, p. 172.

WOW! eBook
www.wowebook.org

Table 5.12

Boolean Logical Compound Assignment Operators

Here are some examples to illustrate the behavior of boolean logical compound
assignment operators:
Click here to view code image
boolean b1 = false, b2 = true, b3 = false;
Boolean b4 = false;
b1 |= true;
// true
b4 ^= b1;
// (1) true, unboxing in (b4 ^ (b1)), boxing on
assignment
b3 &= b1 | b2;
// (2) false, b3 = (b3 & (b1 | b2))
b3 = b3 & b1 | b2;
// (3) true, b3 = ((b3 & b1) | b2)

The assignment at (1) entails unboxing to evaluate the expression on the right-hand side,
followed by boxing to assign the boolean result. It is also instructive to compare how
the assignments at (2) and (3) are performed, as they lead to different results with the same
values of the operands, showing how the precedence affects the evaluation.

5.14 Conditional Operators:

,

The conditional operators && and || are similar to their counterpart logical operators &
and |, except that their evaluation is short-circuited. Given that x and y represent values
of boolean or Boolean expressions, the conditional operators are defined in Table
5.13. In the table, the operators are listed in decreasing precedence order.

Table 5.13

Conditional Operators

Unlike their logical counterparts & and |, which can also be applied to integral operands
for bitwise operations, the conditional operators && and || can be applied only to
boolean operands. Their evaluation results in a boolean value. Truth values for
conditional operators are shown in Table 5.14. Not surprisingly, the conditional operators
have the same truth values as their counterpart logical operators. However, unlike with
their logical counterparts, there are no compound assignment operators for the conditional
operators.

WOW! eBook
www.wowebook.org

Table 5.14

Truth Values for Conditional Operators

Short-Circuit Evaluation
In evaluation of boolean expressions involving conditional AND and OR, the left-hand
operand is evaluated before the right-hand operand, and the evaluation is short-circuited
(i.e., if the result of the boolean expression can be determined from the left-hand operand,
the right-hand operand is not evaluated). In other words, the right-hand operand is
evaluated conditionally.
The binary conditional operators have lower precedence than the arithmetic, relational,
and logical operators, but higher precedence than the assignment operators. Unboxing of
the operand value takes place when necessary, before the operation is performed. The
following examples illustrate usage of conditional operators:
Click here to view code image
Boolean b1 = 4 == 2 && 1 < 4;
boolean b2 = !b1 || 2.5 > 8;
Boolean b3 = !(b1 && b2);
boolean b4 = b1 || !b3 && b2;

//
//
//
//
//
//
//

false, short-circuit evaluated as
(b1 = ((4 == 2) && (1 < 4)))
true, short-circuit evaluated as
(b2 = ((!b1) || (2.5 > 8)))
true
false, short-circuit evaluated as
(b4 = (b1 || ((!b3) && b2)))

The order of evaluation for computing the value stored in the boolean variable b4
proceeds as follows:
Click here to view code image
(b4 = (b1 || ((!b3) && b2)))
(b4 = (false || ((!b3) && b2)))
(b4 = (false || ((!true) && b2)))
(b4 = (false || ((false) && b2)))
(b4 = (false || false))
(b4 = false)

Note that b2 is not evaluated, short-circuiting the evaluation. Example 5.3 illustrates the
short-circuit evaluation of the initialization expressions in the declaration statements given
in the earlier code snippet. In addition, it shows an evaluation (see the declaration of b5)
involving boolean logical operators that always evaluate both operands. See also Example
5.1, p. 153, which uses a similar approach to illustrate the order of operand evaluation in
arithmetic expressions.

WOW! eBook
www.wowebook.org

Example 5.3

Short-Circuit Evaluation Involving Conditional Operators

Click here to view code image
public class ShortCircuit {
public static void main(String[] args) {
// Boolean b1 = 4 == 2 && 1 < 4;
Boolean b1 = operandEval(1, 4 == 2) && operandEval(2, 1 < 4);
System.out.println();
System.out.println(“Value of b1: ” + b1);
// boolean b2 = !b1 || 2.5 > 8;
boolean b2 = !operandEval(1, b1) || operandEval(2, 2.5 > 8);
System.out.println();
System.out.println(“Value of b2: ” + b2);
// Boolean b3 = !(b1 && b2);
Boolean b3 = !(operandEval(1, b1) && operandEval(2, b2));
System.out.println();
System.out.println(“Value of b3: ” + b3);
// boolean b4 = b1 || !b3 && b2;
boolean b4 = operandEval(1, b1) || !operandEval(2, b3) && operandEval(3,
b2);
System.out.println();
System.out.println(“Value of b4: ” + b4);
// boolean b5 = b1 | !b3 & b2;
// Using boolean logical operators
boolean b5 = operandEval(1, b1) | !operandEval(2, b3) & operandEval(3,
b2);
System.out.println();
System.out.println(“Value of b5: ” + b5);
}
static boolean operandEval(int opNum, boolean operand) {
(1)
System.out.print(opNum);
return operand;
}
}

//

Output from the program:
1
Value
1
Value
1
Value
12
Value
123
Value

of b1: false
of b2: true
of b3: true
of b4: false
of b5: false

Short-circuit evaluation can be used to ensure that a reference variable denotes an object
before it is used.
Click here to view code image
if (objRef != null && objRef.equals(other)) { /*…*/ }

The method call is now conditionally dependent on the left-hand operand and will not be
WOW! eBook
www.wowebook.org

executed if the variable objRef has the null reference. If we use the logical & operator
and the variable objRef has the null reference, evaluation of the right-hand operand
will result in a NullPointerException.
In summary, we employ the conditional operators && and || if the evaluation of the righthand operand is conditionally dependent on the left-hand operand. We use the boolean
logical operators & and | if both operands must be evaluated. The subtlety of conditional
operators is illustrated by the following examples:
Click here to view code image
if (i > 0 && i++ < 10) {/*…*/}
if (i > 0 || i++ < 10) {/*…*/}

// i is not incremented if i > 0 is false.
// i is not incremented if i > 0 is true.

5.15 Integer Bitwise Operators: , , ,
A review of integer representation (§5.5, p. 154) is recommended before continuing with
this section on how integer bitwise operators can be applied to values of integral data
types.
Integer bitwise operators include the unary operator ~ (bitwise complement) and the
binary operators & (bitwise AND), | (bitwise inclusive OR), and ^ (bitwise exclusive OR,
also known as bitwise XOR). The operators &, |, and ^ are overloaded, as they can be
applied to boolean or Boolean operands to perform boolean logical operations (§5.13,
p. 184). Although the integer bitwise operators are not on the OCAJP 8 exam, they are
included here to contrast their evaluation with that of their boolean counterparts.
The binary bitwise operators perform bitwise operations between corresponding individual
bit values in the operands. Unary numeric promotion is applied to the operand of the unary
bitwise complement operator ~, and binary numeric promotion is applied to the operands
of the binary bitwise operators. The result is a new integer value of the promoted type,
which can be either int or long.
Given that A and B are corresponding bit values (either 0 or 1) in the left-hand and righthand operands, respectively, these bitwise operators are defined as shown in Table 5.15.
The operators are listed in decreasing precedence order.

Table 5.15

Integer Bitwise Operators

The result of applying bitwise operators between two corresponding bits in the operands is
shown in Table 5.16, where A and B are corresponding bit values in the left-hand righthand operands, respectively. Table 5.16 is analogous to Table 5.11 for boolean logical
WOW! eBook
www.wowebook.org

operators, if we consider bit value 1 to represent true and bit value 0 to represent
false.

Table 5.16

Result Table for Bitwise Operators

Examples of Bitwise Operator Application
Click here to view code image
char v1 = ‘)’;
byte v2 = 13;

// Unicode value 41

int
int
int
int

//
//
//
//

result1
result2
result3
result4

=
=
=
=

~v1;
v1 & v2;
v1 | v2;
v1 ^ v2;

-42
9
45
36

Table 5.17 shows how the result is calculated. Unary and binary numeric promotions are
applied first, converting the operands to int in these cases. Note that the operator
semantics is applied to corresponding individual bits—that is, first bit of left-hand operand
and first bit of right-hand operand, second bit of left-hand operand and second bit of righthand operand, and so on.

Table 5.17

Examples of Bitwise Operations

It is instructive to run examples and print the result of a bitwise operation in different
notations, as shown in Example 5.4. The integer bitwise operators support a programming
technique called bit masking. The value v2 is usually called a bit mask. Depending on the
bitwise operation performed on the value v1 and the mask v2, we see how the resulting
value reflects the bitwise operation performed between the individual corresponding bits
of the value v1 and the mask v2. By choosing appropriate values for the bits in the mask
v2 and the right bitwise operation, it is possible to extract, set, and toggle specific bits in
the value v1.
Methods for converting integers to strings in different notations can be found in the
WOW! eBook
www.wowebook.org

Integer class (§8.3, p. 353). Converting integers to different number systems is
discussed in §5.5, p. 154.
Example 5.4

Bitwise Operations

Click here to view code image
public class BitOperations {
public static void main(String[]
char v1 = ‘)’;
byte v2 = 13;
printIntToStr(“v1:”, v1);
printIntToStr(“v2:”, v2);
printIntToStr(“~v1:”, ~v1);
printIntToStr(“v1 & v2:”, v1 &
printIntToStr(“v1 | v2:”, v1 |
printIntToStr(“v1 ^ v2:”, v1 ^
}

args) {
// Unicode value 41
//
//
//
v2); //
v2); //
v2); //

41
13
-42
9
45
36

public static void printIntToStr(String label, int result) {
System.out.println(label);
System.out.println(“
Binary: ” + Integer.toBinaryString(result));
System.out.println(“
Hex:
” + Integer.toHexString(result));
System.out.println(“
Decimal: ” + result);
}
}

Output from the program:
Click here to view code image
v1:
Binary: 101001
Hex:
29
Decimal: 41
v2:
Binary: 1101
Hex:
d
Decimal: 13
~v1:
Binary:
Hex:
Decimal:
v1 & v2:
Binary:
Hex:
Decimal:
v1 | v2:
Binary:
Hex:
Decimal:
v1 ^ v2:
Binary:
Hex:
Decimal:

11111111111111111111111111010110
ffffffd6
-42
1001
9
9
101101
2d
45
100100
24
36

WOW! eBook
www.wowebook.org

Bitwise Compound Assignment Operators:

,

,

Bitwise compound assignment operators for the bitwise operators are defined in Table
5.18. Type conversions for these operators, when applied to integral operands, are the
same as for other compound assignment operators: an implicit narrowing conversion is
performed on assignment when the destination data type is either byte, short, or
char. These operators can also be applied to boolean operands to perform logical
compound assignments (§5.13, p. 185).

Table 5.18

Bitwise Compound Assignment Operators

Examples of Bitwise Compound Assignment
Click here to view code image
int v0 = -42;
char v1 = ‘)’;
byte v2 = 13;

// 41

v0 &= 15;
v1 |= v2;

//
1…1101 0110 & 0…0000 1111 => 0…0000 0110 (= 6)
// (1) 0…0010 1001 | 0…0000 1101 => 0…0010 1101 (= 45, ‘-‘)

At (1) in these examples, both the char value in v1 and the byte value in v2 are first
promoted to int. The result is implicitly narrowed to the destination type char on
assignment.

Review Questions
5.15 Which of the following expressions evaluate to true?
Select the two correct answers.
(a) (false | true)
(b) (null != null)
(c) (4 <= 4)
(d) (!true)
(e) (true & false)
5.16 Which of the following statements are true?
Select the two correct answers.
(a) The remainder operator % can be used only with integral operands.
(b) Short-circuit evaluation occurs with boolean logical operators.
WOW! eBook
www.wowebook.org

(c) The arithmetic operators *, /, and % have the same level of precedence.
(d) A short value ranges from -128 to +127, inclusive.
(e) (+15) is a legal expression.
5.17 Which statements are true about the lines of output printed by the following
program?
Click here to view code image
public class BoolOp {
static void op(boolean a, boolean b) {
boolean c = a != b;
boolean d = a ^ b;
boolean e = c == d;
System.out.println(e);
}
public static void main(String[] args) {
op(false, false);
op(true, false);
op(false, true);
op(true, true);
}
}

Select the three correct answers.
(a) All lines printed are the same.
(b) At least one line contains false.
(c) At least one line contains true.
(d) The first line contains false.
(e) The last line contains true.
5.18 What is the result of running the following program?
Click here to view code image
public class OperandOrder {
public static void main(String[] args) {
int i = 0;
int[] a = {3, 6};
a[i] = i = 9;
System.out.println(i + ” ” + a[0] + ” ” + a[1]);
}
}

Select the one correct answer.
(a) When run, the program throws an ArrayIndexOutOfBoundsException.
(b) When run, the program will print 9 9 6.
(c) When run, the program will print 9 0 6.
(d) When run, the program will print 9 3 6.
(e) When run, the program will print 9 3 9.
WOW! eBook
www.wowebook.org

5.19 Which statements are true about the output from the following program?
Click here to view code image
public class Logic {
public static void main(String[] args) {
int i = 0;
int j = 0;
boolean t = true;
boolean r;
r = (t & 0 < (i+=1));
r = (t && 0 < (i+=2));
r = (t | 0 < (j+=1));
r = (t || 0 < (j+=2));
System.out.println(i + ” ” + j);
}
}

Select the two correct answers.
(a) The first digit printed is 1.
(b) The first digit printed is 2.
(c) The first digit printed is 3.
(d) The second digit printed is 1.
(e) The second digit printed is 2.
(f) The second digit printed is 3.

5.16 The Conditional Operator:
The ternary conditional operator ?: allows conditional expressions to be defined. The
conditional expression has the following syntax:
Click here to view code image

condition ? expression1 : expression2
It is called ternary because it has three operands. If the boolean expression condition is
true, then expression1 is evaluated; otherwise, expression2 is evaluated. Both
expression1 and expression2 must evaluate to values that can be converted to the type of
the conditional expression. This type is determined from the types of the two expressions.
The value of the expression evaluated is converted to the type of the conditional
expression, and may involve autoboxing and unboxing.
Evaluation of a conditional expression is an example of short-circuit evaluation. As only
one of the two expressions is evaluated, one should be wary of any side effects in a
conditional expression.
In the following code snippet at (1), both expressions in the conditional expression are of
type byte. The type of the conditional expression is therefore byte. That a value of type
byte can be converted to an int by an implicit widening numeric conversion to be
assignment compatible with the int variable daysInFebruary is secondary in
WOW! eBook
www.wowebook.org

determining the type of the conditional expression. Note that the conditional operator at
(1) has higher precedence than the assignment operator =, making it unnecessary to
enclose the conditional expression in parentheses.
Click here to view code image
boolean leapYear = false;
byte v29 = 29;
byte v28 = 28;
int daysInFebruary = leapYear ? v29 : v28;

// (1)

The following examples illustrate the use of conditional expressions. The type of the
conditional expression at (2) is int, and no conversion of any expression value is
necessary. The type of the conditional expression at (3) is double, due to binary numeric
promotion: The int value of the first expressions is promoted to a double. The
compiler reports an error because a double cannot be assigned to an int variable. The
type of the conditional expression at (4) is also double as in (3), but now the double
value is assignment compatible with the double variable minDoubleValue.
Click here to view code image
int i = 3;
int j = 4;
int minValue1 = i < j ? i : j;
// (2) int
int minValue2 = i < j ? i : Double.MIN_VALUE;
// (3) double. Not OK.
double minDoubleValue = i < j ? i : Double.MIN_VALUE; // (4) double

In the following code snippet in (5), the primitive values of the expressions can be boxed
and assigned to an Object reference. In (6), the int value of the first expression can be
boxed in an Integer. The println() method creates and prints a string
representation of any object whose reference value is passed as parameter.
Click here to view code image
// Assume i and j are of type int and initialized correctly.
Object obj = i < j ? i : true;
// (5) value of i boxed in Integer or
//
literal true boxed in Boolean
System.out.println(i < j ? i : “Hi”); // (6) value of i boxed in Integer or
//
String object “Hi”

The conditional expression is not an expression statement. The following code will not
compile:
Click here to view code image
(i < j) ? i : j;

// Compile-time error!

The conditional expression can be nested, and the conditional operator associates from
right to left.
Click here to view code image

a?b:c?d:e?f:g evaluates as (a?b:(c?d:(e?f:g)))
The value of this conditional expression is g if, and only if, a, c, and e are false. A
nested conditional expression is used in the next example. As a convention, the condition
in a conditional expression is enclosed in parentheses to aid reading the code. Typically, a
conditional expression is used when it makes the code easier to read, especially when the
expressions are short and without side effects.
WOW! eBook
www.wowebook.org

Click here to view code image
int n = 3;
String msg = (n==0) ? “no cookies.” : (n==1) ? “one cookie.” : “many
cookies.”;
System.out.println(“You get ” + msg); // You get many cookies.

The conditional operator is the expression equivalent of the if-else statement (§6.2, p.
201).

5.17 Other Operators:

,

,

, ->

The new operator is used to create objects, such as instances of classes and arrays. It is
used with a constructor call to instantiate classes (§3.3, p. 53) and with the [] notation to
create arrays (§3.4, p. 59). It is also used to instantiate anonymous arrays (§3.4, p. 63).
Click here to view code image
Pizza onePizza = new Pizza();

// Create an instance of the Pizza class.

The [] notation is used to declare and construct arrays, and is also to access array
elements (§3.4, p. 58).
Click here to view code image
int[] anArray = new int[5];// Declare and construct an int array of 5
elements.
anArray[4] = anArray[3];
// Element at index 4 gets value of element at
index 3.

The boolean, binary, and infix operator instanceof is used to test the type of an object
(§7.11, p. 320).
Click here to view code image
Pizza myPizza
boolean test1
boolean test2
Pizza.
boolean test3
instance.

= new Pizza();
= myPizza instanceof Pizza; // true.
= “Pizza” instanceof Pizza; // Compile error. String is not
= null instanceof Pizza; // Always false. null is not an

The arrow operator -> is used in the definition of a lambda expression (§10.2, p. 444).
Click here to view code image
java.util.function.Predicate predicate = str -> str.length() % 2 ==
0;
boolean test4 = predicate.test(“The lambda strikes back!”);
// true.

Review Questions
5.20 Which of the following are not operators in Java?
Select the two correct answers.
(a) %
(b) &&
(c) %=
WOW! eBook
www.wowebook.org

(d) &&=
(e) <=
(f) %%
(g) ->
5.21 Which statements when inserted at (1) will not result in a compile-time error?
Click here to view code image
public class RQ05A200 {
public static void main(String[] args) {
int i = 20;
int j = 30;
// (1) INSERT STATEMENT HERE.
}
}

Select the three correct answers.
(a) int result1 = i < j ? i : j * 10D;
(b) int result2 = i < j ? { ++i } : { ++j };
(c) Number number = i < j ? i : j * 10D;
(d) System.out.println(i < j ? i);
(e) System.out.println(i < j ? ++i : ++j);
(f) System.out.println(i == j ? i == j : "i not equal to
j");
5.22 Which statements are true about the following code?
Click here to view code image
public class RQ05A100 {
public static void main(String[] args) {
int n1 = 10, n2 = 10;
int m1 = 20, m2 = 30;
int result = n1 != n2? n1 : m1 != m2? m1 : m2;
System.out.println(result);
}
}

Select the one correct answer.
(a) The program will not compile.
(b) When run, the program throws an ArithmeticException at runtime.
(c) When run, the program will print 10.
(d) When run, the program will print 20.
(e) When run, the program will print 30.

WOW! eBook
www.wowebook.org

Chapter Summary
The following topics were covered in this chapter:
• Type conversion categories and conversion contexts, and which conversions are
permissible in each conversion context.
• Defining and evaluating arithmetic and boolean expressions, and the order in which
operands and operators are evaluated.
• Representing integers in different number systems and in memory.
• Operators in Java, including precedence and associativity rules.

Programming Exercise
5.1 The following program is supposed to calculate and print the time it takes for light
to travel from the sun to the earth. It contains some logical errors. Fix the program
so that it will compile, compute, and print the correct result when run.
Click here to view code image
// File: Sunlight.java
public class Sunlight {
public static void main(String[] args) {
// Distance from sun (150 million kilometers)
int kmFromSun = 150_000_000;
int lightSpeed = 299_792_458; // meters per second
// Convert distance to meters.
int mFromSun = kmFromSun * 1000;
int seconds = mFromSun / lightSpeed;
System.out.print(“Light will use “);
printTime(seconds);
System.out.println(” to travel from the sun to the earth.”);
}
public static void printTime(int sec) {
int min = sec / 60;
sec = sec - (min * 60);
System.out.print(min + ” minute(s) and ” + sec + ” second(s)”);
}
}

WOW! eBook
www.wowebook.org

6. Control Flow

6.1 Overview of Control Flow Statements
Control flow statements govern the flow of control in a program during execution,
meaning the order in which statements are executed in a running program. There are three
main categories of control flow statements:
WOW! eBook
www.wowebook.org

• Selection statements: if, if-else, and switch.
• Iteration statements: while, do-while, basic for, and enhanced for.
• Transfer statements: break, continue, return, try-catch-finally,
throw, and assert.
Only the basic form of the try-catch-finally construct is covered here, and the
assert facility is not in the scope of this book.

6.2 Selection Statements
Java provides selection statements that allow the program to choose between alternative
actions during execution. The choice is based on criteria specified in the selection
statement. These selection statements are
• Simple if statement
• if-else statement
• switch statement

The Simple

Statement

The simple if statement has the following syntax:
if (condition)
statement

It is used to decide whether an action is to be performed or not, based on a condition. The
action to be performed is specified by statement, which can be a single statement or a code
block. The condition must evaluate to a boolean or Boolean value. In the latter case,
the Boolean value is unboxed to the corresponding boolean value.
The semantics of the simple if statement are straightforward. The condition is evaluated
first. If its value is true, statement (called the if block) is executed and then execution
continues with the rest of the program. If the value is false, the if block is skipped and
execution continues with the rest of the program. The semantics are illustrated by the
activity diagram in Figure 6.1a.

WOW! eBook
www.wowebook.org

Figure 6.1

Activity Diagram for if Statements

In the following examples of the if statement, it is assumed that the variables and the
methods have been appropriately defined:
Click here to view code image
if (emergency)
operate();

// emergency is a boolean variable

if (temperature > critical)
soundAlarm();
if (isLeapYear() && endOfCentury())
celebrate();
if (catIsAway()) {
getFishingRod();
goFishing();
}

// Block

Note that statement can be a block, and the block notation is necessary if more than one
statement is to be executed when the condition is true.
Since the condition evaluates to a boolean value, it avoids a common programming
error: using an expression of the form (a=b) as the condition, where inadvertently an
assignment operator is used instead of a relational operator. The compiler will flag this as
an error, unless both a and b are boolean.
Note that the if block can be any valid statement. In particular, it can be the empty
statement (;) or the empty block ({}). A common programming error is inadvertent use
of the empty statement.
Click here to view code image
if (emergency); // Empty if block
operate();
// Executed regardless of whether it was an emergency

The

Statement

The if-else statement is used to decide between two actions, based on a condition. It
has the following syntax:
WOW! eBook
www.wowebook.org

if (condition)
statement1
else
statement2

The condition is evaluated first. If its value is true (or unboxed to true), statement1
(the if block) is executed and then execution continues with the rest of the program. If
the value is false (or unboxed to false), statement2 (the else block) is executed and
then execution continues with the rest of the program. In other words, one of two mutually
exclusive actions is performed. The else clause is optional; if omitted, the construct is
equivalent to the simple if statement. The semantics are illustrated by the activity
diagram in Figure 6.1b.
In the following examples of the if-else statement, it is assumed that all variables and
methods have been appropriately defined:
if (emergency)
operate();
else
joinQueue();
if (temperature > critical)
soundAlarm();
else
businessAsUsual();
if (catIsAway()) {
getFishingRod();
goFishing();
} else
playWithCat();

Since actions can be arbitrary statements, the if statements can be nested.
Click here to view code image
if (temperature >= upperLimit) {
if (danger)
soundAlarm();
if (critical)
evacuate();
else
turnHeaterOff();
} else
turnHeaterOn();

// (1)
// (2) Simple if.
// (3)
// Goes with if at (3).
// Goes with if at (1).

The use of the block notation, {}, can be critical to the execution of if statements. The
if statements (A) and (B) in the following examples do not have the same meaning. The
if statements (B) and (C) are the same, with extra indentation used in (C) to make the
meaning evident. Leaving out the block notation in this case could have catastrophic
consequences: The heater could be turned on when the temperature is above the upper
limit.
Click here to view code image
// (A):
if (temperature > upperLimit) {
if (danger) soundAlarm();

// (1) Block notation.
// (2)

WOW! eBook
www.wowebook.org

} else
turnHeaterOn();
// (B):
if (temperature > upperLimit)
if (danger) soundAlarm();
else turnHeaterOn();
// (C):
if (temperature > upperLimit)
if (danger)
soundAlarm();
else
turnHeaterOn();

// Goes with if at (1).

// (1) Without block notation.
// (2)
// Goes with if at (2).

// (1)
// (2)
// Goes with if at (2).

The rule for matching an else clause is that an else clause always refers to the nearest
if that is not already associated with another else clause. Block notation and proper
indentation can be used to make the meaning obvious.
Cascading if-else statements comprise a sequence of nested if-else statements
where the if block of the next if-else statement is joined to the else clause of the
previous one. The decision to execute a block is then based on all the conditions evaluated
so far.
Click here to view code image
if (temperature >= upperLimit) {
soundAlarm();
turnHeaterOff();
} else if (temperature < lowerLimit) {
soundAlarm();
turnHeaterOn();
} else if (temperature == (upperLimit-lowerLimit)/2) {
doingFine();
} else
noCauseToWorry();

// (1)

// (2)

// (3)
// (4)

The block corresponding to the first if condition that evaluates to true is executed, and
the remaining if statements are skipped. In the preceding example, the block at (3) will
execute only if the conditions at (1) and (2) are false and the condition at (3) is true.
If none of the conditions is true, the block associated with the last else clause is
executed. If there is no last else clause, no actions are performed.

The

Statement

Conceptually, the switch statement can be used to choose one among many alternative
actions, based on the value of an expression. Its general form is as follows:
switch (switch_expression) {
case label1: statement1
case label2: statement2
…
case labeln: statementn
default:
statement
} // end switch

The syntax of the switch statement comprises a switch expression followed by the
WOW! eBook
www.wowebook.org

switch body, which is a block of statements. The switch expression must evaluate to a
value of the following types:
• One of the following primitive data types: char, byte, short, or int
• One of the following wrapper types: Character, Byte, Short, or Integer
• String type
• An enumerated type
Note that the type of the switch expression cannot be boolean, long, or floatingpoint. The statements in the switch body can be labeled, thereby defining entry points in
the switch body where control can be transferred depending on the value of the
switch expression. The execution of the switch statement is as follows:
• The switch expression is evaluated first. If the value is a wrapper type, an
unboxing conversion is performed.
• The value of the switch expression is compared with the case labels. Control is
transferred to the statement associated with the case label that is equal to the value
of the switch expression. After execution of the associated statement, control falls
through to the next statement unless this was the last statement declared or control
was transferred out of the switch statement.
• If no case label is equal to the value of the switch expression, the statement
associated with the default label is executed. After execution of the associated
statement, control falls through to the next statement unless this was the last
statement declared or control was transferred out of the switch statement.
Figure 6.2 illustrates the flow of control through a switch statement where the
default label is declared last.

Figure 6.2

Activity Diagram for a switch Statement

All labels (including the default label) are optional, and can be defined in any order in
WOW! eBook
www.wowebook.org

the switch body. At most one default label can be present in a switch statement. If
no valid case labels are found and the default label is omitted, the whole switch
statement is skipped.
The case labels are constant expressions whose values must be unique, meaning no
duplicate values are allowed. In fact, a case label must be a compile-time constant
expression whose value is assignable to the type of the switch expression (§5.2, p. 147).
In particular, all case label values must be in the range of the type of the switch
expression. The type of the case label cannot be boolean, long, or floating-point.
The compiler is able to generate efficient code for a switch statement, as this statement
only tests for equality between the switch expression and the constant value of the
case labels, so as to determine which code to execute at runtime. In contrast, a sequence
of if statements determines the flow of control at runtime, based on arbitrary conditions
whose value might be possible to determine only at runtime.
In Example 6.1, depending on the value of the howMuchAdvice parameter, different
advice is printed in the switch statement at (1) in the method dispenseAdvice().
The example shows the output when the value of the howMuchAdvice parameter is
LOTS_OF_ADVICE. In the switch statement, the associated statement at (2) is
executed, giving one piece of advice. Control then falls through to the statement at (3),
giving the second advice. Control next falls through to (4), dispensing the third piece of
advice, and finally execution of the break statement at (5) causes control to exit the
switch statement. Without the break statement at (5), control would continue to fall
through the remaining statements—in this case, to the statement at (6) being executed.
Execution of the break statement in a switch body transfers control out of the
switch statement (§6.4, p. 221). If the parameter howMuchAdvice has the value
MORE_ADVICE, then the advice at both (3) and (4) is given. The value
LITTLE_ADVICE results in only one piece of advice at (4) being given. Any other value
results in the default action, which announces that there is no advice.
The associated statement of a case label can be a list of statements (which need not be a
statement block). The case label is prefixed to the first statement in each case. This is
illustrated by the associated statement for the case label LITTLE_ADVICE in Example
6.1, which comprises statements (4) and (5).

WOW! eBook
www.wowebook.org

Example 6.1

Fall-Through in a switch Statement

Click here to view code image
public class Advice {
private static final int LITTLE_ADVICE = 0;
private static final int MORE_ADVICE = 1;
private static final int LOTS_OF_ADVICE = 2;
public static void main(String[] args) {
dispenseAdvice(LOTS_OF_ADVICE);
}
public static void dispenseAdvice(int howMuchAdvice) {
switch (howMuchAdvice) {
// (1)
case LOTS_OF_ADVICE:
System.out.println(“See no evil.”);
// (2)
case MORE_ADVICE:
System.out.println(“Speak no evil.”); // (3)
case LITTLE_ADVICE:
System.out.println(“Hear no evil.”); // (4)
break;
// (5)
default:
System.out.println(“No advice.”);
// (6)
}
}
}

Output from the program:
See no evil.
Speak no evil.
Hear no evil.

Example 6.2 makes use of a break statement inside a switch statement to convert a
char value representing a digit to the corresponding word in English. Note that the
break statement is the last statement in the list of statements associated with each case
label. It is easy to think that the break statement is a part of the switch statement
syntax, but technically it is not.

WOW! eBook
www.wowebook.org

Example 6.2

Using break in a switch Statement

Click here to view code image
public class Digits {
public static void main(String[] args) {
System.out.println(digitToString(‘7’) + ” ” + digitToString(‘8’) + ” ” +
digitToString(‘6’));
System.out.println(digitToString(‘2’) + ” ” + digitToString(‘a’) + ” ” +
digitToString(‘5’));
}
public static String digitToString(char digit) {
String str = ””;
switch(digit) {
case ‘1’: str = “one”;
break;
case ‘2’: str = “two”;
break;
case ‘3’: str = “three”; break;
case ‘4’: str = “four”; break;
case ‘5’: str = “five”; break;
case ‘6’: str = “six”;
break;
case ‘7’: str = “seven”; break;
case ‘8’: str = “eight”; break;
case ‘9’: str = “nine”; break;
case ‘0’: str = “zero”; break;
default: System.out.println(digit + ” is not a digit!”);
}
return str;
}
}

Output from the program:
seven eight six
a is not a digit!
two five

Several case labels can prefix the same statement. They will all result in the associated
statement being executed. This behavior is illustrated in Example 6.3 for the switch
statement at (1).
The first statement in the switch body must have a case or default label, or
otherwise it will be unreachable. This statement will never be executed, because control
can never be transferred to it. The compiler will flag this as an error. An empty switch
block is perfectly legal, but not of much use.
Since each action associated with a case label can be an arbitrary statement, it can be
another switch statement. In other words, switch statements can be nested. Since a
switch statement defines its own local block, the case labels in an inner block do not
conflict with any case labels in an outer block. Labels can be redefined in nested blocks;
in contrast, variables cannot be redeclared in nested blocks (§4.4, p. 117). In Example 6.3,
an inner switch statement is defined at (2), which allows further refinement of the action
to take on the value of the switch expression in cases where multiple labels are used in
the outer switch statement. A break statement terminates the innermost switch
statement in which it is executed.
WOW! eBook
www.wowebook.org

Example 6.3

Nested switch Statement

Click here to view code image
public class Seasons {
public static void main(String[] args) {
int monthNumber = 11;
switch(monthNumber) {
// (1) Outer
case 12: case 1: case 2:
System.out.println(“Snow in the winter.”);
break;
case 3: case 4: case 5:
System.out.println(“Green grass in the spring.”);
break;
case 6: case 7: case 8:
System.out.println(“Sunshine in the summer.”);
break;
case 9: case 10: case 11:
// (2)
switch(monthNumber) { // Nested switch
(3) Inner
case 10:
System.out.println(“Halloween.”);
break;
case 11:
System.out.println(“Thanksgiving.”);
break;
} // End nested switch
// Always printed for case labels 9, 10, 11
System.out.println(“Yellow leaves in the fall.”);
// (4)
break;
default:
System.out.println(monthNumber + ” is not a valid month.”);
}
}
}

Output from the program:
Thanksgiving.
Yellow leaves in the fall.

Example 6.4 illustrates using strings in a switch statement. The thing to note is what
constitutes a constant string expression that can be used as a case label. The case labels
in (3), (4), (5), and (6) are all valid constant string expressions, as the compiler can figure
out their values at compile time. String literals, used in (3) and (6), and constant field
values, declared in (1) and (2a), and used in (4) and (5), are all valid case labels. In
contrast, the HOT reference from declarations (2b) and (2c) cannot be used as a case
label. From the declaration in (2a), the compiler cannot guarantee that the value of the
reference will not change at runtime. From the declaration in (2c), it cannot deduce the
value at compile time, as the constructor must be run to construct the value.
Switching on strings is essentially based on equality comparison of integer values that are
hash values of strings, followed by an object equality test to rule out the possibility of
collision between two different strings having the same hash value. Switching on strings
should be used judiciously, as it is less efficient than switching on integers. Switching on
strings is not advisable if the values being switched on are not already strings.
WOW! eBook
www.wowebook.org

Example 6.4

Strings in switch Statement

Click here to view code image
public class SwitchingOnAString {
public static final String MEDIUM = “Medium”;
//
public static final String HOT = “Hot”;
//
//public static
String HOT = “Hot”;
//
lablel
//public static final String HOT = new String(“Hot”);//
lablel
public static void main(String[] args) {
String spiceLevel = “Medium_Hot”;
switch (spiceLevel) {
case “Mild”:
case MEDIUM + “_” + HOT:
System.out.println(“Enjoy your meal!”);
break;
case HOT:
System.out.println(“Have fun!”);
break;
case “Suicide”:
System.out.println(“Good luck!”);
break;
default:
System.out.println(“You being funny?”);
}
}

(1)
(2a)
(2b) Not OK as case
(2c) Not OK as case

// (3)
// (4)

// (5)

// (6)

}

Output from the program:
Enjoy your meal!

Example 6.5 illustrates the use of enum types in a switch statement. The enum type
SpiceGrade is defined at (1). The type of the switch expression is SpiceGrade.
Note that the enum constants are not specified with their fully qualified name (see (2a)).
Using the fully qualified name results in a compile-time error, as shown at (2b). Only
enum constants that have the same enum type as the switch expression can be specified
as case label values.
The semantics of the switch statement are the same as described earlier. However, if a
switch expression evaluates to the null reference, a NullPointerException will
be thrown. Switching on enumerated values is essentially based on equality comparison of
unique integer values that are ordinal values assigned by the compiler to the constants of
an enum type.

WOW! eBook
www.wowebook.org

Example 6.5

Enums in switch Statement

Click here to view code image
enum SpiceGrade {
MILD, MEDIUM_HOT, HOT, SUICIDE;
}

// (1)

public class SwitchingFun {
public static void main(String[] args) {
SpiceGrade spicing = SpiceGrade.HOT;
switch (spicing) {
case HOT:
// (2a) OK!
//
case SpiceGrade.HOT:
// (2b) Compile-time error!
System.out.println(“Have fun!”);
break;
case SUICIDE:
System.out.println(“Good luck!”);
break;
default:
// Can only be MILD or
MEDIUM_HOT.
System.out.println(“Enjoy you meal!”);
}
}
}

Output from the program:
Have fun!

Review Questions
6.1 What will be the result of attempting to compile and run the following class?
Click here to view code image
public class IfTest {
public static void main(String[] args) {
if (true)
if (false)
System.out.println(“a”);
else
System.out.println(“b”);
}
}

Select the one correct answer.
(a) The code will fail to compile because the syntax of the if statement is
incorrect.
(b) The code will fail to compile because the compiler will not be able to determine
which if statement the else clause belongs to.
(c) The code will compile correctly, and display the letter a at runtime.
(d) The code will compile correctly, and display the letter b at runtime.
(e) The code will compile correctly, but will not display any output.
WOW! eBook
www.wowebook.org

6.2 Which of the following statements are true?
Select the three correct answers.
(a) The condition in an if statement can have method calls.
(b) If a and b are of type boolean or Boolean, the expression (a = b) can
be the condition of an if statement.
(c) An if statement can have either an if clause or an else clause.
(d) The statement if (false) ; else ; is illegal.
(e) Only expressions that evaluate or can be unboxed to a boolean value can be
used as the condition in an if statement.
6.3 What, if anything, is wrong with the following code?
void test(int x) {
switch (x) {
case 1:
case 2:
case 0:
default:
case 4:
}
}

Select the one correct answer.
(a) The variable x does not have the right type for a switch expression.
(b) The case label 0 must precede the case label 1.
(c) Each case section must end with a break statement.
(d) The default label must be the last label in the switch statement.
(e) The body of the switch statement must contain at least one statement.
(f) There is nothing wrong with the code.
6.4 What will be the result of attempting to compile and run the following program?
Click here to view code image
public class Switching {
public static void main(String[] args) {
final int iLoc = 3;
switch (6) {
case 1:
case iLoc:
case 2 * iLoc:
System.out.println(“I am not OK.”);
default:
System.out.println(“You are OK.”);
case 4:
System.out.println(“It’s OK.”);
}
}
}

WOW! eBook
www.wowebook.org

Select the one correct answer.
(a) The code will fail to compile because of the case label value 2 * iLoc.
(b) The code will fail to compile because the default label is not specified last
in the switch statement.
(c) The code will compile correctly and will print the following at runtime:
I am not OK.
You are OK.
It’s OK.

(d) The code will compile correctly and will print the following at runtime:
You are OK.
It’s OK.

(e) The code will compile correctly and will print the following at runtime:
It’s OK.

6.5 What will be the result of attempting to compile and run the following program?
Click here to view code image
public class MoreSwitching {
public static void main(String[] args) {
final int iLoc = 3;
Integer iRef = 5;
switch (iRef) {
default:
System.out.println(“You are OK.”);
case 1:
case iLoc:
case 2 * iLoc:
System.out.println(“I am not OK.”);
break;
case 4:
System.out.println(“It’s OK.”);
}
}
}

Select the one correct answer.
(a) The code will fail to compile because the type of the switch expression is not
valid.
(b) The code will compile correctly and will print the following at runtime:
You are OK.
I am not OK.

(c) The code will compile correctly and will print the following at runtime:
You are OK.
I am not OK.
It’s OK.

(d) The code will compile correctly and will print the following at runtime:
It’s OK.

6.6 Which case label declaration can be inserted at (1) so that the following program
WOW! eBook
www.wowebook.org

will compile, run, and print Hi, TomTom!?
Click here to view code image
public class Switcheroo {
public static void main(String[] args) {
final String TOM1 = “Tom”;
String TOM2 = “Tom”;
final String TOM3 = new String(“Tom”);
switch (“TomTom”) {
default:
System.out.println(“Whatever!”);
break;
//
(1) INSERT case LABEL DECLARATION HERE.
System.out.println(“Hi, TomTom!”);
}
}
}

Select the four correct answers.
(a) case "TomTom":
(b) case TOM1 + TOM1:
(c) case TOM1 + TOM2:
(d) case TOM1 + TOM3:
(e) case TOM2 + TOM3:
(f) case "Tom" + TOM1:
(g) case "Tom" + TOM2:
(h) case "Tom" + TOM3:
(i) case 'T' + 'o' + 'm' + TOM1:
(j) case "T" + 'o' + 'm' + TOM1:

6.3 Iteration Statements
Loops allow a block of statements to be executed repeatedly (that is, iterated). A boolean
condition (called the loop condition) is commonly used to determine when to terminate the
loop. The statements executed in the loop constitute the loop body. The loop body can be a
single statement or a block.
Java provides three language constructs for loop construction:
• The while statement
• The do-while statement
• The basic for statement
These loops differ in the order in which they execute the loop body and test the loop
condition. The while loop and the basic for loop test the loop condition before
executing the loop body, whereas the do-while loop tests the loop condition after
WOW! eBook
www.wowebook.org

execution of the loop body.
In addition to the basic for loop, a specialized loop called the enhanced for loop (also
called the for-each loop) simplifies iterating over arrays and collections. We will use the
notations for(;;) and for(:) to designate the basic for loop and the enhanced for
loop, respectively.

The

Statement

The syntax of the while loop is
while (loop_condition)
loop_body

The loop condition is evaluated before executing the loop body. The while statement
executes the loop body as long as the loop condition is true. When the loop condition
becomes false, the loop is terminated and execution continues with the statement
immediately following the loop. If the loop condition is false to begin with, the loop
body is not executed at all. In other words, a while loop can execute zero or more times.
The loop condition must evaluate to a boolean or a Boolean value. In the latter case,
the reference value is unboxed to a boolean value. The flow of control in a while
statement is shown in Figure 6.3.

Figure 6.3

Activity Diagram for the while Statement

The while statement is normally used when the number of iterations is not known.
while (noSignOfLife())
keepLooking();

Since the loop body can be any valid statement, inadvertently terminating each line with
the empty statement (;) can give unintended results. Always using a block statement as
the loop body helps to avoid such problems.
Click here to view code image
while (noSignOfLife());
keepLooking();

The

// Empty statement as loop body!
// Statement not in the loop body.

Statement

The syntax of the do-while loop is
do
loop_body
while (loop_condition);

In a do-while statement, the loop condition is evaluated after executing the loop body.
WOW! eBook
www.wowebook.org

The loop condition must evaluate to a boolean or Boolean value. The value of the
loop condition is subjected to unboxing if it is of the type Boolean. The do-while
statement executes the loop body until the loop condition becomes false. When the loop
condition becomes false, the loop is terminated and execution continues with the
statement immediately following the loop. Note that the loop body is executed at least
once. Figure 6.4 illustrates the flow of control in a do-while statement.

Figure 6.4

Activity Diagram for the do-while Statement

The loop body in a do-while loop is invariably a statement block. It is instructive to
compare the while and do-while loops. In the examples that follow, the mice might
never get to play if the cat is not away, as in the loop at (1). The mice do get to play at
least once (at the peril of losing their life) in the loop at (2).
Click here to view code image
while (cat.isAway()) {
mice.play();
}

// (1)

do {
mice.play();
} while (cat.isAway());

// (2)

The

Statement

The for(;;) loop is the most general of all the loops. It is mostly used for countercontrolled loops, in which the number of iterations is known beforehand.
The syntax of the loop is as follows:
Click here to view code image

for (initialization; loop_condition; update_expression)
loop_body
The initialization usually declares and initializes a loop variable that controls the
execution of the loop body. The loop condition must evaluate to a boolean or Boolean
value. In the latter case, the reference value is converted to a boolean value by
unboxing. The loop condition usually involves the loop variable, and if the loop condition
is true, the loop body is executed; otherwise, execution continues with the statement
following the for(;;) loop. After each iteration (that is, execution of the loop body),
the update expression is executed. This usually modifies the value of the loop variable to
ensure eventual loop termination. The loop condition is then tested to determine whether
the loop body should be executed again. Note that the initialization is executed only once,
WOW! eBook
www.wowebook.org

on entry into the loop. The semantics of the for(;;) loop are illustrated in Figure 6.5,
and are summarized by the following equivalent while loop code template:
initialization
while (loop_condition) {
loop_body
update_expression
}

Figure 6.5

Activity Diagram for the for Statement

The following code creates an int array and sums the values in the array:
Click here to view code image
int sum = 0;
int[] array = {12, 23, 5, 7, 19};
for (int index = 0; index < array.length; index++)
sum += array[index];

// (1)

The loop variable index is declared and initialized in the initialization section of the
loop. It is incremented in the update expression section. This loop is an example of a
forward for(;;) loop, where the loop variable is incremented.
The next code snippet is an example of a backward for(;;) loop, where the loop
variable is decremented to sum the values in the array:
Click here to view code image
int sum = 0;
int[] array = {12, 23, 5, 7, 19};
for (int index = array.length - 1; index >= 0; index—)
sum += array[index];

It is instructive to compare the specification of the loop header in the forward
and backward for(;;) loops in these examples.
The for(;;) loop defines a local block so that the scope of this declaration is the
for(;;) block, which comprises the initialization, the loop condition, the loop body,
and the update expression sections. Any variable declared in the for(;;) block,
therefore, is not accessible after the for(;;) loop terminates. The loop at (1) earlier
showed how a declaration statement can be specified in the initialization section. Such a
WOW! eBook
www.wowebook.org

declaration statement can also specify a comma-separated list of variables:
Click here to view code image
for (int i = 0, j = 1, k = 2; … ; …) …;

// (2)

The variables i, j, and k in the declaration statement all have type int. All variables
declared in the initialization section are local variables in the for(;;) block and obey
the scope rules for local blocks. The following code will not compile, however, as variable
declarations of different types (in this case, int and String) require declaration
statements that are terminated by semicolons:
Click here to view code image
for (int i = 0, String str = “@”; … ; …) …;

// (3) Compile-time error

The initialization section can also be a comma-separated list of expression statements
(§3.2, p. 50). Any value returned by an expression statement is discarded. For example,
the loop at (2) can be rewritten by factoring out the variable declaration:
Click here to view code image
int i, j, k; // Variable declaration
for (i = 0, j = 1, k = 2; … ; …) …;

// (4) Only initialization

The initialization section is now a comma-separated list of three expressions. The
expressions in such a list are always evaluated from left to right, and their values are
discarded. Note that the variables i, j, and k at (4) are not local to the loop.
Declaration statements cannot be mixed with expression statements in the initialization
section, as is the case at (5) in the following example. Factoring out the variable
declaration, as at (6), leaves a legal comma-separated list of expression statements.
Click here to view code image
// (5) Not legal and ugly:
for (int i = 0, System.out.println(“This won’t do!”); flag; i++) { // Error!
// loop body
}
// (6) Legal, but still ugly:
int i;
// Declaration factored out.
for (i = 0, System.out.println(“This is legal!”); flag; i++) {
// OK.
// loop body
}

The update expression can also be a comma-separated list of expression statements. The
following code specifies a for(;;) loop that has a comma-separated list of three
variables in the initialization section, and a comma-separated list of two expressions in the
update expression section:
Click here to view code image
// Legal usage but not recommended.
int[][] sqMatrix = { {3, 4, 6}, {5, 7, 4}, {5, 8, 9} };
for (int i = 0, j = sqMatrix[0].length - 1, asymDiagonal = 0; //
initialization
i < sqMatrix.length;
// loop
condition
i++, j—)
// update expression
asymDiagonal += sqMatrix[i][j];
// loop body
WOW! eBook
www.wowebook.org

All sections in the for(;;) header are optional. Any or all of them can be left empty,
but the two semicolons are mandatory. In particular, leaving out the loop condition
signifies that the loop condition is true. The “crab”, (;;), can be used to construct an
infinite loop, where termination is presumably achieved through code in the loop body
(see the next section on transfer statements):
Click here to view code image
for (;;) doProgramming();

The

// Infinite loop

Statement

The enhanced for loop is convenient when we need to iterate over an array or a
collection, especially when some operation needs to be performed on each element of the
array or collection. In this section we discuss iterating over arrays; in §10.1, p. 423, we
take a look at the for(:) loop for iterating over ArrayLists.
Earlier in this chapter we used a for(;;) loop to sum the values of elements in an int
array:
Click here to view code image
int sum = 0;
int[] intArray = {12, 23, 5, 7, 19};
for (int index = 0; index < intArray.length; index++) { // (1) using for(;;)
loop
sum += intArray[index];
}

The for(;;) loop at (1) is rewritten using the for(:) loop in Figure 6.6.

Figure 6.6

Enhanced for Statement

The body of the loop is executed for each element in the array, where the variable
element successively denotes the current element in the array intArray. When the
loop terminates, the variable sum will contain the sum of all elements in the array. We do
not care about the position of the elements in the array, just that the loop iterates over all
elements of the array.
From Figure 6.6 we see that the for(:) loop header has two parts. The expression must
evaluate to a reference value that refers to an array—that is, the array we want to iterate
over. The array can be an array of primitive values or objects, or even an array of arrays.
The expression is evaluated only once. The element declaration specifies a local variable
that can be assigned a value of the element type of the array. The type of the array
intArray in Figure 6.6 is int[], and the element type is int. The element variable of
type int can be assigned int values from the array of int. However, this assignment
might require either a boxing or an unboxing conversion, with optional widening
WOW! eBook
www.wowebook.org

conversion.
The element variable is local to the loop block and is not accessible after the loop
terminates. Also, changing the value of the current variable does not change any value in
the array. The loop body, which can be a simple statement or a statement block, is
executed for each element in the array and there is no danger of any out-of-bounds errors.
The for(:) loop has its limitations. Specifically, we cannot change element values, and
this kind of loop does not provide any provision for positional access using an index. The
for(:) loop only increments by one and always in a forward direction. It does not allow
iterations over several arrays simultaneously. Under such circumstances, the for(;;)
loop can be more convenient.
Here are some code examples of legal for(:) loops:
Click here to view code image
// Some 1-dim arrays:
int[]
intArray =
{10, 20, 30};
Integer[] intObjArray = {10, 20, 30};
String[] strArray =
{“one”, “two”};
// Some 2-dim arrays:
Object[][] objArrayOfArrays = {intObjArray, strArray};
Number[][] numArrayOfArrays = {{1.5, 2.5}, intObjArray, {100L, 200L}};
int[][]
intArrayOfArrays = {{20}, intArray, {40}};
// Iterate over an array of Strings.
// Expression type is String[], and element type is String.
// String is assignable to Object (widening conversion).
for (Object obj : strArray) {}
// Iterate over an array of ints.
// Expression type is int[], and element type is int.
// int is assignable to Integer (boxing conversion)
for (Integer iRef : intArrayOfArrays[0]){}
// Iterate over an array of Integers.
// Expression type is Integer[], and element type is Integer.
// Integer is assignable to int (unboxing conversion)
for (int i : intObjArray){}
// Iterate over a 2-dim array of ints.
// Outer loop: expression type is int[][], and element type is int[].
// Inner loop: expression type is int[], and element type is int.
for (int[] row : intArrayOfArrays)
for (int val : row) {}
// Iterate over a 2-dim array of Numbers.
// Outer loop: expression type is Number[][], and element type is Number[].
// Outer loop: Number[] is assignable to Object[] (widening conversion).
// Inner loop: expression type is Object[], and element type is Object.
for (Object[] row : numArrayOfArrays)
for (Object obj : row) {}
// Outer loop: expression type is Integer[][], and element type is Integer[].
// Outer loop: Integer[] is assignable to Number[].
// Inner loop: expression type is int[], and element type is int.
// Inner loop: int is assignable to double.
for (Number[] row : new Integer[][] {intObjArray, intObjArray, intObjArray})
WOW! eBook
www.wowebook.org

for (double num : new int[] {}) {}

Here are some code examples of for(:) loops that are not legal:
Click here to view code image
// Expression type is Number[][], and element type is Number[].
// Number[] is not assignable to Number.
for (Number num : numArrayOfArrays) {}
// Compile-time error.
// Expression type is Number[], and element type is Number.
// Number is not assignable to int.
for (int row : numArrayOfArrays[0]) {}
// Compile-time error.
// Outer loop: expression type is int[][], and element type is int[].
// int[] is not assignable to Integer[].
for (Integer[] row : intArrayOfArrays)
// Compile-time error.
for (int val : row) {}
// Expression type is Object[][], and element type is Object[].
// Object[] is not assignable to Integer[].
for (Integer[] row : objArrayOfArrays) {}
// Compile-time error.
// Outer loop: expression type is String[], and element type is String.
// Inner loop: expression type is String, which is not legal here. Not an
array.
for (String str : strArray)
for (char val : str) {}
// Compile-time error.

When using the for(:) loop to iterate over an array, the two main causes of errors are an
expression in the loop header that does not represent an array and/or an element type of
the array that is not assignable to the local variable declared in the loop header.

6.4 Transfer Statements
Java provides six language constructs for transferring control in a program:
• break
• continue
• return
• try-catch-finally
• throw
• assert
This section discusses the first three statements. Except for the assert statement (not on
the OCAJP8 exam), the remaining statements are discussed in subsequent sections.
Note that Java does not have a goto statement, although goto is a reserved word.

Labeled Statements
A statement may have a label:
label : statement
WOW! eBook
www.wowebook.org

A label is any valid identifier; it always immediately precedes the statement. Label names
exist in their own namespace, so that they do not conflict with names of packages, classes,
interfaces, methods, fields, and local variables. The scope of a label is the statement
prefixed by the label, meaning that it cannot be redeclared as a label inside the labeled
statement—analogous to the scope of local variables.
Click here to view code image
L1: if (i > 0) {
L1: System.out.println(i);
}

// (1) Not OK. Label redeclared.

L1: while (i < 0) {
L2: System.out.println(i);
}

// (2) OK.

L1: {
int j = 10;
System.out.println(j);
}

// (3) OK. Labeled block.

L1: try {
// (4) OK. Labeled try-catch-finally block.
int j = 10, k = 0;
L2: System.out.println(j/k);
} catch (ArithmeticException ae) {
L3: ae.printStackTrace();
} finally {
L4: System.out.println(“Finally done.”);
}

A statement can have multiple labels:
Click here to view code image
LabelA: LabelB: System.out.println(“Mutliple labels. Use judiciously.”);

A declaration statement cannot have a label:
Click here to view code image
L0: int i = 0;

// Compile-time error!

A labeled statement is executed as if it was unlabeled, unless it is the break or
continue statement. This behavior is discussed in the next two subsections.

The

Statement

The break statement comes in two forms: unlabeled and labeled.
Click here to view code image
break;
break label;

// the unlabeled form
// the labeled form

The unlabeled break statement terminates loops (for(;;), for(:), while, dowhile) and switch statements, and transfers control out of the current context (i.e., the
closest enclosing block). The rest of the statement body is skipped, and execution
continues after the enclosing statement.
In Example 6.6, the break statement at (1) is used to terminate a for(;;) loop. Control
is transferred to (2) when the value of i is equal to 4 at (1), skipping the rest of the loop
WOW! eBook
www.wowebook.org

body and terminating the loop.
Example 6.6 also shows that the unlabeled break statement terminates only the
innermost loop or switch statement that contains the break statement. The break
statement at (3) terminates the inner for(;;) loop when j is equal to 2, and execution
continues in the outer switch statement at (4) after the for(;;) loop.
Example 6.6

The break Statement

Click here to view code image
class BreakOut {
public static void main(String[] args) {
System.out.println(“i
sqrt(i)”);
for (int i = 1; i <= 5; ++i) {
if (i == 4)
break;
// (1) Terminate loop. Control to
(2).
// Rest of loop body skipped when i gets the value 4.
System.out.printf(“%d
%.2f%n”, i, Math.sqrt(i));
} // end for
// (2) Continue here.
int n = 2;
switch (n) {
case 1:
System.out.println(n);
break;
case 2:
System.out.println(“Inner for(;;) loop: “);
for (int j = 0; j <= n; j++) {
if (j == 2)
break;
// (3) Terminate loop. Control to
(4).
System.out.println(“j = ” + j);
}
default:
System.out.println(“default: n = ” + n); // (4) Continue here.
}
}
}

Output from the program:
i
sqrt(i)
1
1.00
2
1.41
3
1.73
Inner for(;;) loop:
j = 0
j = 1
default: n = 2

A labeled break statement can be used to terminate any labeled statement that contains
the break statement. Control is then transferred to the statement following the enclosing
labeled statement. In the case of a labeled block, the rest of the block is skipped and
execution continues with the statement following the block:
Click here to view code image
WOW! eBook
www.wowebook.org

out:
{
// …
if (j == 10) break out;
System.out.println(j);
// …
}
// (3) Continue here.

// Label.
// (1) Labeled block.
// (2) Terminate block. Control to (3).
// Rest of the block not executed if j == 10.

In Example 6.7, the program continues to add the elements below the diagonal of a square
matrix until the sum is greater than 10. Two nested for loops are defined at (1) and (2).
The outer loop is labeled outer at (1). The unlabeled break statement at (3) transfers
control to (5) when it is executed; that is, it terminates the inner loop and control is
transferred to the statement after the inner loop. The labeled break statement at (4)
transfers control to (6) when it is executed; that is, it terminates both the inner and the
outer loop, transferring control to the statement after the loop labeled outer.
Example 6.7

Labeled break Statement

Click here to view code image
class LabeledBreakOut {
public static void main(String[] args) {
int[][] squareMatrix = {{4, 3, 5}, {2, 1, 6}, {9, 7, 8}};
int sum = 0;
outer: for (int i = 0; i < squareMatrix.length; ++i){
// (1) label
for (int j = 0; j < squareMatrix[i].length; ++j) { // (2)
if (j == i) break;
// (3) Terminate inner loop. Control to
(5).
System.out.println(“Element[” + i + “, ” + j + “]: ” +
squareMatrix[i][j]);
sum += squareMatrix[i][j];
if (sum > 10) break outer; // (4) Terminate both loops. Control to
(6).
} // end inner loop
// (5) Continue with update expression in the outer loop header.
} // end outer loop
// (6) Continue here.
System.out.println(“sum: ” + sum);
}
}

Output from the program:
Element[1, 0]: 2
Element[2, 0]: 9
sum: 11

The

Statement

Like the break statement, the continue statement comes in two forms: unlabeled and
labeled.
Click here to view code image
continue;
continue label;

// the unlabeled form
// the labeled form

The continue statement can be used only in a for(;;), for(:), while, or doWOW! eBook
www.wowebook.org

while loop to prematurely stop the current iteration of the loop body and proceed with
the next iteration, if possible. In the case of the while and do-while loops, the rest of
the loop body is skipped—that is, the current iteration is stopped, with execution
continuing with the loop condition. In the case of the for(;;) loop, the rest of the loop
body is skipped, with execution continuing with the update expression.
In Example 6.8, an unlabeled continue statement is used to skip an iteration in a
for(;;) loop. Control is transferred to (2) when the value of i is equal to 4 at (1),
skipping the rest of the loop body and continuing with the update expression in the
for(;;) statement.
Example 6.8

continue Statement

Click here to view code image
class Skip {
public static void main(String[] args) {
System.out.println(“i
sqrt(i)”);
for (int i = 1; i <= 5; ++i) {
if (i == 4) continue;
// (1) Control to (2).
// Rest of loop body skipped when i has the value 4.
System.out.printf(“%d
%.2f%n”, i, Math.sqrt(i));
// (2) Continue with update expression in the loop header.
} // end for
}
}

Output from the program:
i
1
2
3
5

sqrt(i)
1.00
1.41
1.73
2.24

A labeled continue statement must occur within a labeled loop that has the same label.
Execution of the labeled continue statement then transfers control to the end of that
enclosing labeled loop. In Example 6.9, the unlabeled continue statement at (3)
transfers control to (5) when it is executed; that is, the rest of the loop body is skipped and
execution continues with the update expression in the inner loop. The labeled continue
statement at (4) transfers control to (6) when it is executed; that is, it terminates the inner
loop but execution continues with the update expression in the loop labeled outer. It is
instructive to compare the output from Example 6.7 (labeled break) and that from
Example 6.9 (labeled continue).

WOW! eBook
www.wowebook.org

Example 6.9

Labeled continue Statement

Click here to view code image
class LabeledSkip {
public static void main(String[] args) {
int[][] squareMatrix = {{4, 3, 5}, {2, 1, 6}, {9, 7, 8}};
int sum = 0;
outer: for (int i = 0; i < squareMatrix.length; ++i){
// (1) label
for (int j = 0; j < squareMatrix[i].length; ++j) { // (2)
if (j == i) continue;
// (3) Control to
(5).
System.out.println(“Element[” + i + “, ” + j + “]: ” +
squareMatrix[i][j]);
sum += squareMatrix[i][j];
if (sum > 10) continue outer;
// (4) Control to
(6).
// (5) Continue with update expression in the inner loop header.
} // end inner loop
// (6) Continue with update expression in the outer loop header.
} // end outer loop
System.out.println(“sum: ” + sum);
}
}

Output from the program:
Element[0,
Element[0,
Element[1,
Element[1,
Element[2,
sum: 25

The

1]:
2]:
0]:
2]:
0]:

3
5
2
6
9

Statement

The return statement is used to stop execution of a method (or a constructor) and
transfer control back to the calling code (also called the caller or invoker). The usage of
the two forms of the return statement is dictated by whether that statement is used in a
void or a non-void method (Table 6.1). The first form does not return any value to the
calling code, but the second form does. Note that the keyword void does not represent
any type.

Table 6.1

The return Statement

In Table 6.1, the expression must evaluate to a primitive value or a reference value, and its
type must be assignable to the return type specified in the method header (§5.6, p. 158,
and §7.9, p. 312). See also the discussion on covariant return in connection with method
overriding in §7.2, p. 268.
WOW! eBook
www.wowebook.org

As can be seen from Table 6.1, a void method need not have a return statement—in
which case the control typically returns to the caller after the last statement in the
method’s body has been executed. However, a void method can specify only the first
form of the return statement. This form of the return statement can also be used in
constructors, as they likewise do not return a value.
Table 6.1 also shows that the first form of the return statement is not allowed in a nonvoid method. The second form of the return statement is mandatory in a non-void
method, if the method execution is not terminated programmatically—for example, by
throwing an exception. Example 6.10 illustrates the use of the return statement
summarized in Table 6.1. A recommended best practice is to document the value returned
by a method in a Javadoc comment using the @return tag.
Example 6.10

The return Statement

Click here to view code image
public class ReturnDemo {
public static void main (String[] args) { // (1) void method can use
return.
if (args.length == 0) return;
output(checkValue(args.length));
}
static void output(int value) {
System.out.println(value);
return ‘a’;
}
static int checkValue(int i) {
statement

// (2) void method need not use return.
// Not OK. Cannot return a value.

// (3) Non-void method: Any return
//

if (i > 3)
return i;
else
return 2.0;

must return a value.

// OK.
// Not OK. double not assignable to int.

}
static int absentMinded() {
throw new RuntimeException();

// (4) Non-void method.
// OK: No return statement provided, but
// method terminates by throwing an

exception.
}
}

Review Questions
6.7 What will be the result of attempting to compile and run the following code?
Click here to view code image
class MyClass {
public static void main(String[] args) {
boolean b = false;
int i = 1;
do {
WOW! eBook
www.wowebook.org

i++;
b = ! b;
} while (b);
System.out.println(i);
}
}

Select the one correct answer.
(a) The code will fail to compile because b is an invalid condition for the dowhile statement.
(b) The code will fail to compile because the assignment b = ! b is not allowed.
(c) The code will compile without error, and will print 1 at runtime.
(d) The code will compile without error, and will print 2 at runtime.
(e) The code will compile without error, and will print 3 at runtime.
6.8 What will be the output when running the following program?
Click here to view code image
public class StillMyClass {
public static void main(String[] args) {
int i = 0;
int j;
for (j = 0; j < 10; ++j) { i++; }
System.out.println(i + ” ” + j);
}
}

Select the two correct answers.
(a) The first number printed will be 9.
(b) The first number printed will be 10.
(c) The first number printed will be 11.
(d) The second number printed will be 9.
(e) The second number printed will be 10.
(f) The second number printed will be 11.
6.9 Which of the following for statements is valid?
Select the one correct answer.
(a) int j = 10; for (int i = 0, j += 90; i < j; i++) { j-; }
(b) for (int i = 10; i = 0; i--) {}
(c) for (int i = 0, j = 100; i < j; i++, --j) {;}
(d) int i, j; for (j = 100; i < j; j--) { i += 2; }
(e) int i = 100; for ((i > 0); i--) {}
WOW! eBook
www.wowebook.org

6.10 What will be the result of attempting to compile and run the following program?
Click here to view code image
class AnotherClass {
public static void main(String[]
int i = 0;
for (; i < 10; i++) ;
//
for (i = 0;; i++) break;
//
for (i = 0; i < 10;) i++;
//
for (;;) ;
//
}
}

args) {
(1)
(2)
(3)
(4)

Select the one correct answer.
(a) The code will fail to compile because of errors in the for loop at (1).
(b) The code will fail to compile because of errors in the for loop at (2).
(c) The code will fail to compile because of errors in the for loop at (3).
(d) The code will fail to compile because of errors in the for loop at (4).
(e) The code will compile without error, and the program will run and terminate
without any output.
(f) The code will compile without error, but will never terminate when run.
6.11 Which of the following statements are valid when occurring on their own?
Select the three correct answers.
(a) while () break;
(b) do { break; } while (true);
(c) if (true) { break; }
(d) switch (1) { default: break; }
(e) for (;true;) break;
6.12 Given the following code fragment, which of the following lines will be a part of
the output?
Click here to view code image
outer:
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 2; j++) {
if (i == j) {
continue outer;
}
System.out.println(“i=” + i + “, j=” + j);
}
}

Select the two correct answers.
(a) i=1, j=0
(b) i=0, j=1
WOW! eBook
www.wowebook.org

(c) i=1, j=2
(d) i=2, j=1
(e) i=2, j=2
(f) i=3, j=3
(g) i=3, j=2
6.13 What will be the result of attempting to compile and run the following code?
Click here to view code image
class MyClass {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
switch(i) {
case 0:
System.out.println(i);
}
if (i) {
System.out.println(i);
}
}
}
}

Select the one correct answer.
(a) The code will fail to compile because of an illegal switch expression in the
switch statement.
(b) The code will fail to compile because of an illegal condition in the if
statement.
(c) The code will compile without error, and will print the numbers 0 through 10
at runtime.
(d) The code will compile without error, and will print the number 0 at runtime.
(e) The code will compile without error, and will print the number 0 twice at
runtime.
(f) The code will compile without error, and will print the numbers 1 through 10 at
runtime.
6.14 Which declarations, when inserted at (1), will result in the program compiling and
printing 90 at runtime?
Click here to view code image
public class RQ400A10 {
public static void main(String[] args) {
// (1) INSERT DECLARATION HERE
int sum = 0;
for (int i : nums)
sum += i;
System.out.println(sum);
}
}
WOW! eBook
www.wowebook.org

Select the two correct answers.
(a) Object[] nums = {20, 30, 40};
(b) Number[] nums = {20, 30, 40};
(c) Integer[] nums = {20, 30, 40};
(d) int[] nums = {20, 30, 40};
(e) None of the above
6.15 Which method declarations, when inserted at (1), will result in the program
compiling and printing 90 when run?
Click here to view code image
public class RQ400A30 {
public static void main(String[] args) {
doIt();
}
// (1) INSERT METHOD DECLARATION HERE.
}

Select the two correct answers.
(a)
public static void doIt() {
int[] nums = {20, 30, 40};
for (int sum = 0, i : nums)
sum += i;
System.out.println(sum);
}

(b)
Click here to view code image
public static void doIt() {
for (int sum = 0, i : {20, 30, 40})
sum += i;
System.out.println(sum);
}

(c)
public static void doIt() {
int sum = 0;
for (int i : {20, 30, 40})
sum += i;
System.out.println(sum);
}

(d)
Click here to view code image
public static void doIt() {
int sum = 0;
for (int i : new int[] {20, 30, 40})
sum += i;
System.out.println(sum);
}

WOW! eBook
www.wowebook.org

(e)
public static void doIt() {
int[] nums = {20, 30, 40};
int sum = 0;
for (int i : nums)
sum += i;
System.out.println(sum);
}

6.5 Stack-Based Execution and Exception Propagation
An exception in Java signals the occurrence of an error situation due to the violation of
some semantic constraint of the Java programming language during execution—for
example, a requested file cannot be found, an array index is out of bounds, or a network
link failed. Explicit checks in the code for such situations can easily result in
incomprehensible code. Java provides an exception handling mechanism for
systematically dealing with such error situations.
The exception mechanism is built around the throw-and-catch paradigm. To throw an
exception is to signal that an unexpected condition has occurred. To catch an exception is
to take appropriate action to deal with the exception. An exception is caught by an
exception handler, and the exception need not be caught in the same context in which it
was thrown. The runtime behavior of the program determines which exceptions are
thrown and how they are caught. The throw-and-catch principle is embedded in the trycatch-finally construct.
Several threads can be executing at the same time in the JVM. Each thread has its own
JVM stack (also called a runtime stack, call stack, and invocation stack in the literature)
that is used to handle execution of methods. Each element on the stack (called an
activation frame or a stack frame) corresponds to a method call. Each new call results in a
new activation frame being pushed on the stack, which stores all the pertinent information
such as the local variables. The method with the activation frame on the top of the stack is
the one currently executing. When this method finishes executing, its activation frame is
popped from the top of the stack. Execution then continues in the method corresponding to
the activation frame that is now uncovered on the top of the stack. The methods on the
stack are said to be active, as their execution has not completed. At any given time, the
active methods on a JVM stack make up what is called the stack trace of a thread’s
execution.
Example 6.11 is a simple program to illustrate method execution. It calculates the average
for a list of integers, given the sum of all the integers and the number of integers. It uses
three methods:
• The method main() calls the method printAverage() with parameters giving
the total sum of the integers and the total number of integers, (1).
• The method printAverage() in turn calls the method computeAverage(),
(3).
• The method computeAverage() uses integer division to calculate the average
and returns the result, (7).
WOW! eBook
www.wowebook.org

Example 6.11

Method Execution

Click here to view code image
public class Average1 {
public static void main(String[] args) {
printAverage(100, 20);
System.out.println(“Exit main().”);
}

// (1)
// (2)

public static void printAverage(int totalSum, int totalNumber) {
int average = computeAverage(totalSum, totalNumber);
// (3)
System.out.println(“Average = ” +
// (4)
totalSum + ” / ” + totalNumber + ” = ” + average);
System.out.println(“Exit printAverage().”);
// (5)
}
public static int computeAverage(int sum, int number) {
System.out.println(“Computing average.”);
return sum/number;
}

// (6)
// (7)

}

Output of program execution:
Computing average.
Average = 100 / 20 = 5
Exit printAverage().
Exit main().

Execution of Example 6.11 is illustrated in Figure 6.7. Each method execution is shown as
a box with the local variables declared in the method. The height of the box indicates how
long a method is active. Before the call to the method System.out.println() at (6)
in Figure 6.7, the stack trace comprises the three active methods: main(),
printAverage(), and computeAverage(). The result 5 from the method
computeAverage() is returned at (7) in Figure 6.7. The output from the program
corresponds with the sequence of method calls in Figure 6.7. As the program terminates
normally, this program behavior is called normal execution.

WOW! eBook
www.wowebook.org

Figure 6.7

Method Execution

If the method call at (1) in Example 6.11
Click here to view code image
printAverage(100, 20);

// (1)

is replaced with
Click here to view code image
printAverage(100, 0);

// (1)

and the program is run again, the output is as follows:
Click here to view code image
Computing average.
Exception in thread “main” java.lang.ArithmeticException: / by zero
at Average1.computeAverage(Average1.java:18)
at Average1.printAverage(Average1.java:10)
at Average1.main(Average1.java:5)

Figure 6.8 illustrates the program execution when the method printAverage() is
called with the arguments 100 and 0 at (1). All goes well until the return statement at
(7) in the method computeAverage() is executed. An error condition occurs in
calculating the expression sum/number, because integer division by 0 is an illegal
WOW! eBook
www.wowebook.org

operation. This error condition is signaled by the JVM by throwing an ArithmeticException (§6.6, p. 233). This exception is propagated by the JVM through the JVM
stack as explained next.

Figure 6.8

Exception Propagation

Figure 6.8 illustrates the case where an exception is thrown and the program does not take
any explicit action to deal with the exception. In Figure 6.8, execution of the
computeAverage() method is suspended at the point where the exception is thrown.
The execution of the return statement at (7) never gets completed. Since this method
does not have any code to deal with the exception, its execution is likewise terminated
abruptly and its activation frame popped. We say that the method completes abruptly. The
exception is then offered to the method whose activation is now on the top of the stack
(method printAverage()). This method does not have any code to deal with the
exception either, so its execution completes abruptly. The statements at (4) and (5) in the
method printAverage() never get executed. The exception now propagates to the last
active method (method main()). This does not deal with the exception either. The
main() method also completes abruptly. The statement at (2) in the main() method
never gets executed. Since the exception is not caught by any of the active methods, it is
dealt with by the main thread’s default exception handler. The default exception handler
WOW! eBook
www.wowebook.org

usually prints the name of the exception, with an explanatory message, followed by a
printout of the stack trace at the time the exception was thrown. An uncaught exception, as
in this case, results in the death of the thread in which the exception occurred.
If an exception is thrown during the evaluation of the left-hand operand of a binary
expression, then the right-hand operand is not evaluated. Similarly, if an exception is
thrown during the evaluation of a list of expressions (e.g., a list of actual parameters in a
method call), evaluation of the rest of the list is skipped.
If the line numbers in the stack trace are not printed in the output as shown previously, use
the following command to run the program:
Click here to view code image
>java -Djava.compiler=NONE Average1

6.6 Exception Types
Exceptions in Java are objects. All exceptions are derived from the
java.lang.Throwable class. Figure 6.9 shows a partial hierarchy of classes derived
from the Throwable class. The two main subclasses Exception and Error
constitute the main categories of throwables, the term used to refer to both exceptions and
errors. Figure 6.9 also shows that not all exception classes are found in the java.lang
package.

WOW! eBook
www.wowebook.org

Figure 6.9

Partial Exception Inheritance Hierarchy

The Throwable class provides a String variable that can be set to provide a detail
message when an exception is constructed. The purpose of the detail message is to provide
more information about the actual exception. All classes of throwables define a oneparameter constructor that takes a string as the detail message.
The class Throwable provides the following common methods to query an exception:

WOW! eBook
www.wowebook.org

String getMessage()

Returns the detail message.
void printStackTrace()

Prints the stack trace on the standard error stream. The stack trace comprises the
method invocation sequence on the JVM stack when the exception was thrown. The
stack trace can also be written to a PrintStream or a PrintWriter by
supplying such a destination as an argument to one of the two overloaded
printStackTrace() methods. Any suppressed exceptions associated with an
exception on the stack trace are also printed. It will also print the cause of an
exception (which is also an exception) if one is available.
String toString()

Returns a short description of the exception, which typically comprises the class
name of the exception together with the string returned by the getMessage()
method.
In dealing with throwables, it is important to recognize situations in which particular
throwables can occur, and the source that is responsible for throwing them. By source we
mean:
• The JVM that is responsible for throwing the throwable, or
• The throwable that is explicitly thrown programmatically by the code in the
application or by any API used by the application.
In further discussion of exception types, we provide an overview of situations in which
selected throwables can occur and the source responsible for throwing them.

The

Class

The class Exception represents exceptions that a program would normally want to
catch. Its subclass RuntimeException represents many common programming errors
that can manifest at runtime (see the next subsection). Other subclasses of the
Exception class define other categories of exceptions, such as I/O-related exceptions in
the java.io package (IOException, FileNotFoundException,
EOFException) and database-related exceptions in the java.sql package
(SQLException).
ClassNotFoundException
The subclass ClassNotFoundException signals that the JVM tried to load a class by
its string name, but the class could not be found. A typical example of this situation is
when the class name is misspelled while starting program execution with the java
command. The source in this case is the JVM throwing the exception to signal that the
class cannot be found and therefore execution cannot be started.

WOW! eBook
www.wowebook.org

The

Class

Runtime exceptions are all subclasses of the java.lang.RuntimeException class,
which is a subclass of the Exception class. As these runtime exceptions are usually
caused by program bugs that should not occur in the first place, it is usually more
appropriate to treat them as faults in the program design and let them be handled by the
default exception handler.
ArithmeticException
This exception represents situations where an illegal arithmetic operation is attempted,
such as integer division by 0. It is typically thrown by the JVM. See Chapter 5 for details
on illegal arithmetic operations.
ArrayIndexOutOfBoundsException
Java provides runtime checking of the array index value, meaning out-of-bounds array
indices. The subclass ArrayIndexOutOfBoundsException represents exceptions
thrown by the JVM that signal out-of-bound errors specifically for arrays—that is, an error
in which an invalid index is used to access an element in the array. The index value must
satisfy the relation 0 ≤ index value < length of the array. See §3.4, p. 58, covering arrays.
ClassCastException
This exception is thrown by the JVM to signal that an attempt was made to cast a
reference value to a type that was not legal, such as casting the reference value of an
Integer object to the Long type. Casting reference values is discussed in §7.11, p. 320.
IllegalArgumentException and NumberFormatException
The IllegalArgumentException is thrown programmatically to indicate that a
method was called with an illegal or inappropriate argument. For example, the
ofPattern(String pattern) method in the
java.time.format.DateTimeFormatter class throws an
IllegalArgumentException when the letter pattern passed as an argument is
invalid (§11.4, p. 495).
The class NumberFormatException is a subclass of the
IllegalArgumentException class, and is specialized to signal problems when
converting a string to a numeric value if the format of the characters in the string is not
appropriate for the conversion. This exception is also thrown programmatically. The
numeric wrapper classes all have methods that throw this exception when conversion from
a string to a numeric value is not possible (§8.3, p. 346).

WOW! eBook
www.wowebook.org

NullPointerException
This exception is typically thrown by the JVM when an attempt is made to use the null
value as a reference value to refer to an object. This might involve calling an instance
method using a reference that has the null value, or accessing a field using a reference
that has the null value. This programming error has made this exception one of the
exceptions most often thrown by the JVM.

The

Class

The class Error and its subclasses define errors that are invariably never explicitly
caught and are usually irrecoverable. Not surprisingly, most such errors are signaled by the
JVM. Apart from the subclasses mentioned in the following subsections, other subclasses
of the java.lang.Error class define errors that indicate class linkage
(LinkageError), thread (ThreadDeath), and virtual machine
(VirtualMachineError) problems.
AssertionError
The subclass AssertionError of the java.lang.Error class is used by the Java
assertion facility. This error is thrown by the JVM in response to the condition in the
assert statement evaluating to false. The assertion facility is not discussed in this
book.
StackOverflowError
This error occurs when the JVM stack has no more room for new method activation
frames. In such a case, we say that the stack has overflowed. This situation can occur when
method execution in an application recurses too deeply. Here is a recursive method to
illustrate stack overflow:
Click here to view code image
public void callMe() {
System.out.println(“Don’t do this at home!”);
callMe();
}

Once this method is called, it will keep on calling itself until the JVM stack is full,
resulting in the StackOverflowError being thrown by the JVM.

Checked and Unchecked Exceptions
Except for RuntimeException, Error, and their subclasses, all exceptions are
checked exceptions. That is, the compiler ensures that if a method can throw a checked
exception, directly or indirectly, the method must explicitly deal with it. The method must
either catch the exception and take the appropriate action, or pass on the exception to its
caller (§6.9, p. 251).
Exceptions defined by the Error and RuntimeException classes and their
subclasses are known as unchecked exceptions, meaning that a method is not obliged to
deal with these kinds of exceptions (shown with gray color in Figure 6.9). They are either
WOW! eBook
www.wowebook.org

irrecoverable (exemplified by the Error class), in which case the program should not
attempt to deal with them, or they are programming errors (exemplified by the
RuntimeException class) and should usually be dealt with as such, and not as
exceptions.

Defining Customized Exceptions
Customized exceptions are usually defined to provide fine-grained categorization of error
situations, instead of using existing exception classes with descriptive detail messages to
differentiate among the various situations. New customized exceptions are usually defined
by either extending the Exception class or one of its checked subclasses, thereby
making the new exceptions checked, or extending the RuntimeException subclass to
create new unchecked exceptions.
As exceptions are defined by classes, they can declare fields and methods, thereby
providing more information as to their cause and remedy when they are thrown and
caught. The super() call can be used to set the detail message for the exception. Note
that the exception class must be instantiated to create an exception object that can be
thrown and subsequently caught and dealt with. The following code sketches a class
declaration for an exception that can include all pertinent information about the exception.
At a minimum, the new exception class should provide a constructor to set the detail
message.
Click here to view code image
public class EvacuateException extends Exception {
// Data
Date date;
Zone zone;
TransportMode transport;
// Constructor
public EvacuateException(Date d, Zone z, TransportMode t) {
// Call the constructor of the superclass
super(“Evacuation of zone ” + z);
// …
}
// Methods
// …
}

Several examples in subsequent sections illustrate exception handling.

6.7 Exception Handling:

,

, and

The mechanism for handling exceptions is embedded in the try-catch-finally
construct, which has the following basic form:
Click here to view code image
try {
statements
} catch (exception_type1 parameter1) {
statements
}
…

// try block
// uni-catch clause

WOW! eBook
www.wowebook.org

catch (exception_typen parametern) {
statements
} finally {
statements
}

// uni-catch clause
// finally clause

A few aspects about the syntax of this construct should be noted. For each try block,
there can be zero or more catch clauses (i.e., it can have multiple catch clauses), but
only one finally clause. The catch clauses and the finally clause must always
appear in conjunction with a try block, and in the right order. A try block must be
followed by at least one catch clause, or a finally clause must be specified. In
addition to the try block, each catch clause and the finally clause specify a block,
{ }. The block notation is mandatory.
Exceptions thrown during execution of the try block can be caught and handled in a
catch clause. Each catch clause defines an exception handler. The header of the
catch clause specifies exactly one exception parameter. The exception type must be of
the Throwable class or one of its subclasses. The type of the exception parameter of a
catch clause is specified by a single exception type in the syntax given earlier, and such
a catch clause is called a uni-catch clause.
A finally clause is guaranteed to be executed, regardless of the cause of exit from the
try block, or whether any catch clause was executed. Figure 6.10 shows three typical
scenarios of control flow through the try-catch-finally construct.

Figure 6.10

The try-catch-finally Construct

The try block, the catch clause, and the finally clause of a try-catchfinally construct can contain arbitrary code, which means that a try-catchWOW! eBook
www.wowebook.org

finally construct can be nested in any block of the try-catch-finally construct.
However, such nesting can easily make the code difficult to read and is best avoided, if
possible.

The

Block

The try block establishes a context for exception handling. Termination of a try block
occurs as a result of encountering an exception, or from successful execution of the code
in the try block.
The catch clauses are skipped for all normal exits from the try block when no
exceptions are thrown, and control is transferred to the finally clause if one is
specified ((1) in Figure 6.10).
For all exits from the try block resulting from exceptions, control is transferred to the
catch clauses—if any such clauses are specified—to find a matching catch clause ((2)
in Figure 6.10). If no catch clause matches the thrown exception, control is transferred
to the finally clause if one is specified ((3) in Figure 6.10).

The

Clause

Only an exit from a try block resulting from an exception can transfer control to a
catch clause. A catch clause can catch the thrown exception only if the exception is
assignable to the parameter in the catch clause (§7.8, p. 311). The code of the first such
catch clause is executed, and all other catch clauses are ignored.
On exit from a catch clause, normal execution continues unless there is any uncaught
exception that has been thrown and not handled. If this is the case, the method is aborted
and the exception is propagated up the JVM stack as explained in §6.5, p. 230.
After a catch clause has been executed, control is always transferred to the finally
clause if one is specified. This is always true as long as there is a finally clause,
regardless of whether the catch clause itself throws an exception.
In Example 6.12, the method printAverage() calls the method
computeAverage() in a try-catch construct at (4). The catch clause is declared
to catch exceptions of type ArithmeticException. The catch clause handles the
exception by printing the stack trace and some additional information at (7) and (8),
respectively. Normal execution of the program is illustrated in Figure 6.11, which shows
that the try block is executed but no exceptions are thrown, with normal execution
continuing after the try-catch construct. This corresponds to Scenario 1 in Figure 6.10.

WOW! eBook
www.wowebook.org

Figure 6.11

Exception Handling (Scenario 1)

WOW! eBook
www.wowebook.org

Example 6.12

The try-catch Construct

Click here to view code image
public class Average2 {
public static void main(String[] args) {
printAverage(100, 20);
System.out.println(“Exit main().”);
}
public static void printAverage(int totalSum, int totalNumber) {
try {
int average = computeAverage(totalSum, totalNumber);
System.out.println(“Average = ” +
totalSum + ” / ” + totalNumber + ” = ” + average);
} catch (ArithmeticException ae) {
ae.printStackTrace();
System.out.println(“Exception handled in printAverage().”);
}
System.out.println(“Exit printAverage().”);
}
public static int computeAverage(int sum, int number) {
System.out.println(“Computing average.”);
return sum/number;
}

// (1)
// (2)

// (3)
// (4)
// (5)
// (6)
// (7)
// (8)
// (9)

// (10)
// (11)

}

Output from the program, with call printAverage(100, 20) at (1):
Computing average.
Average = 100 / 20 = 5
Exit printAverage().
Exit main().

Output from the program, with call printAverage(100, 0) at (1):
Click here to view code image
Computing average.
java.lang.ArithmeticException: / by zero
at Average2.computeAverage(Average2.java:23)
at Average2.printAverage(Average2.java:11)
at Average2.main(Average2.java:5)
Exception handled in printAverage().
Exit printAverage().
Exit main().

However, if we run the program in Example 6.12 with the following call in (1):
printAverage(100, 0)

an ArithmeticException is thrown by the integer division operator in the method
computeAverage(). In Figure 6.12 we see that the execution of the method
compute-Average() is stopped and the exception propagated to method
printAverage(), where it is handled by the catch clause at (6). Normal execution
of the method continues at (9) after the try-catch construct, as witnessed by the output
from the statements at (9) and (2). This corresponds to Scenario 2 in Figure 6.10.
WOW! eBook
www.wowebook.org

Figure 6.12

Exception Handling (Scenario 2)

In Example 6.13, the main() method calls the printAverage() method in a trycatch construct at (1). The catch clause at (3) is declared to catch exceptions of type
ArithmeticException. The printAverage() method calls the
computeAverage() method in a try-catch construct at (7), but here the catch
clause is declared to catch exceptions of type IllegalArgumentException.
Execution of the program is illustrated in Figure 6.13, which shows that the
ArithmeticException is first propagated to the catch clause in the
printAverage() method. Because this catch clause cannot handle this exception, it
is propagated further to the catch clause in the main() method, where it is caught and
handled. Normal execution continues at (6) after the exception is handled.

WOW! eBook
www.wowebook.org

Figure 6.13

Exception Handling (Scenario 3)

Note that the execution of the try block at (7) in the printAverage() method is
never completed: The statement at (9) is never executed. The catch clause at (10) is
skipped. The execution of the printAverage() method is aborted: The statement at
(13) is never executed, and the exception is propagated. This corresponds to Scenario 3 in
Figure 6.10.

WOW! eBook
www.wowebook.org

Example 6.13

Exception Propagation

Click here to view code image
public class Average3 {
public static void main(String[] args) {
try {
printAverage(100, 0);
} catch (ArithmeticException ae) {
ae.printStackTrace();
System.out.println(“Exception handled in main().”);
}
System.out.println(“Exit main().”);
}
public static void printAverage(int totalSum, int totalNumber) {
try {
int average = computeAverage(totalSum, totalNumber);
System.out.println(“Average = ” +
totalSum + ” / ” + totalNumber + ” = ” + average);
} catch (IllegalArgumentException iae) {
iae.printStackTrace();
System.out.println(“Exception handled in printAverage().”);
}
System.out.println(“Exit printAverage().”);
}
public static int computeAverage(int sum, int number) {
System.out.println(“Computing average.”);
return sum/number;
}

//
//
//
//
//

(1)
(2)
(3)
(4)
(5)

// (6)

// (7)
// (8)
// (9)
// (10)
// (11)
// (12)
// (13)

// (14)
// (15)

}

Output from the program:
Click here to view code image
Computing average.
java.lang.ArithmeticException: / by zero
at Average3.computeAverage(Average3.java:28)
at Average3.printAverage(Average3.java:16)
at Average3.main(Average3.java:6)
Exception handled in main().
Exit main().

The scope of the parameter name in the catch clause is the clause itself. As mentioned
earlier, the type of the exception object must be assignable to the type of the argument in
the catch clause (§7.8, p. 311). In the body of the catch clause, the exception object
can be queried like any other object by using the parameter name. The javac compiler
also complains if a catch clause for a superclass exception shadows the catch clause
for a subclass exception, as the catch clause of the subclass exception will never be
executed (a situation known as unreachable code). The following example shows
incorrect order of the catch clauses at (1) and (2), which will result in a compile-time
error: The superclass Exception will shadow the subclass ArithmeticException.
Click here to view code image
…
// Compiler-time error at (1).
WOW! eBook
www.wowebook.org

catch (Exception e) {
System.out.println(e);
} catch (ArithmeticException e) {
System.out.println(e);
}
…

The

// (1) superclass
// (2) subclass

Clause

If the try block is executed, then the finally clause is guaranteed to be executed,
regardless of whether any catch clause was executed. Since the finally clause is
always executed before control transfers to its final destination, the finally clause can
be used to specify any clean-up code (e.g., to free resources such as files and net
connections). However, the try-with-resources statement provides a better solution for
handling resources, and eliminates use of the finally clause in many cases. But that is a
story for another day, as this topic is not on the OCAJP8 exam.
A try-finally construct can be used to control the interplay between two actions that
must be executed in the correct order, possibly with other intervening actions. In the
following code, the operation in the calculateAverage() method is dependent on
the success of the sumNumbers() method, which is checked by the value of the sum
variable before calling the calculateAverage() method:
Click here to view code image
int sum = 0;
try {
sum = sumNumbers();
// other actions
} finally {
if (sum > 0) calculateAverage();
}

This code guarantees that if the try block is entered, the sumNumbers() method will
be executed first, and later the calculateAverage() method will be executed in the
finally clause, regardless of how execution proceeds in the try block. We can, if
desired, include any catch clauses to handle any exceptions.
If the finally clause neither throws an exception nor executes a control transfer
statement like a return or a labeled break, the execution of the try block or any
catch clause determines how execution proceeds after the finally clause (Figure
6.10, p. 239).
• If no exception is thrown during execution of the try block or the exception has
been handled in a catch clause, normal execution continues after the finally
clause.
• If there is any uncaught exception (either because no catch clause was found or
because the catch clause threw an exception), the method is aborted and the
exception is propagated after the execution of the finally clause.
The output of Example 6.14 shows that the finally clause at (9) is executed, regardless
of whether an exception is thrown in the try block at (3). If an exception is thrown, it is
WOW! eBook
www.wowebook.org

caught and handled by the catch clause at (6). After the execution of the finally
clause at (9), normal execution continues at (10).
Example 6.14

The try-catch-finally Construct

Click here to view code image
public class Average4 {
public static void main(String[] args) {
printAverage(100, 20);
System.out.println(“Exit main().”);
}
public static void printAverage(int totalSum, int totalNumber) {
try {
int average = computeAverage(totalSum, totalNumber);
System.out.println(“Average = ” +
totalSum + ” / ” + totalNumber + ” = ” + average);
} catch (ArithmeticException ae) {
ae.printStackTrace();
System.out.println(“Exception handled in printAverage().”);
} finally {
System.out.println(“Finally done.”);
}
System.out.println(“Exit printAverage().”);
}
public static int computeAverage(int sum, int number) {
System.out.println(“Computing average.”);
return sum/number;
}

// (1)
// (2)

// (3)
// (4)
// (5)
//
//
//
//

(6)
(7)
(8)
(9)

// (10)

// (11)
// (12)

}

Output from the program, with the call printAverage(100, 20) at (1):
Computing average.
Average = 100 / 20 = 5
Finally done.
Exit printAverage().
Exit main().

Output from the program, with the call printAverage(100, 0) at (1):
Click here to view code image
Computing average.
java.lang.ArithmeticException: / by zero
at Average4.computeAverage(Average4.java:25)
at Average4.printAverage(Average4.java:11)
at Average4.main(Average4.java:5)
Exception handled in printAverage().
Finally done.
Exit printAverage().
Exit main().

On exiting from the finally clause, if there is any uncaught exception, the method is
aborted and the exception propagated as explained earlier. This is illustrated in Example
6.15. The method printAverage() is aborted after the finally clause at (6) has
been executed, as the ArithmeticException thrown at (9) is not handled by
WOW! eBook
www.wowebook.org

any method. In this case, the exception is handled by the default exception handler.
Notice the difference in the output from Example 6.14 and Example 6.15.
Example 6.15

The try-finally Construct

Click here to view code image
public class Average5 {
public static void main(String[] args) {
printAverage(100, 0);
System.out.println(“Exit main().”);
}

// (1)
// (2)

public static void printAverage(int totalSum, int totalNumber) {
try {
// (3)
int average = computeAverage(totalSum, totalNumber);
// (4)
System.out.println(“Average = ” +
// (5)
totalSum + ” / ” + totalNumber + ” = ” + average);
} finally {
// (6)
System.out.println(“Finally done.”);
}
System.out.println(“Exit printAverage().”);
// (7)
}
public static int computeAverage(int sum, int number) {
System.out.println(“Computing average.”);
return sum/number;
}

// (8)
// (9)

}

Output from the program:
Click here to view code image
Computing average.
Finally done.
Exception in thread “main” java.lang.ArithmeticException: / by zero
at Average5.computeAverage(Average5.java:22)
at Average5.printAverage(Average5.java:11)
at Average5.main(Average5.java:4)

If the finally clause executes a control transfer statement, such as a return or a
labeled break, this control transfer statement determines how the execution will proceed
—regardless of how the try block or any catch clause was executed. In particular, a
value returned by a return statement in the finally clause will supercede any value
returned by a return statement in the try block or a catch clause.
Example 6.16 shows how the execution of a control transfer statement such as a return
in the finally clause affects the program execution. The first output from the program
shows that the average is computed but the value returned is from the return statement
at (8) in the finally clause, not from the return statement at (6) in the try block.
The second output shows that the ArithmeticException thrown in the
computeAverage() method and propagated to the printAverage() method is
nullified by the return statement in the finally clause. Normal execution continues
after the return statement at (8), with the value 0 being returned from the
WOW! eBook
www.wowebook.org

printAverage() method.
If the finally clause throws an exception, this exception is propagated with all its
ramifications—regardless of how the try block or any catch clause was executed. In
particular, the new exception overrules any previously uncaught exception.
Example 6.16

The finally Clause and the return Statement

Click here to view code image
public class Average6 {
public static void main(String[] args) {
System.out.println(“Average: ” + printAverage(100, 20));
System.out.println(“Exit main().”);
}
public static int printAverage(int totalSum, int totalNumber) {
int average = 0;
try {
average = computeAverage(totalSum, totalNumber);
System.out.println(“Average = ” +
totalSum + ” / ” + totalNumber + ” = ” + average);
return average;
} finally {
System.out.println(“Finally done.”);
return average*2;
}
}
public static int computeAverage(int sum, int number) {
System.out.println(“Computing average.”);
return sum/number;
}

// (1)
// (2)

// (3)
// (4)
// (5)
// (6)
// (7)
// (8)

// (9)
// (10)

}

Output from the program, with call printAverage(100, 20) in (1):
Computing average.
Average = 100 / 20 = 5
Finally done.
Average: 10
Exit main().

Output from the program, with call printAverage(100, 0) in (1):
Computing average.
Finally done.
Average: 0
Exit main().

6.8 The

Statement

Earlier examples in this chapter have shown how an exception can be thrown implicitly by
the JVM during execution. Now we look at how an application can programmatically
throw an exception using the throw statement. The general format of the throw
statement is as follows:
Click here to view code image
WOW! eBook
www.wowebook.org

throw object_reference_expression;

The compiler ensures that the object reference expression is of the type Throwable class
or one of its subclasses. At runtime a NullPointerException is thrown by the JVM
if the object reference expression is null. This ensures that a Throwable will always
be propagated. A detail message is often passed to the constructor when the exception
object is created.
Click here to view code image
throw new ArithmeticException(“Integer division by 0”);

When an exception is thrown, normal execution is suspended. The runtime system
proceeds to find a catch clause that can handle the exception. The search starts in the
context of the current try block, propagating to any enclosing try blocks and through
the JVM stack to find a handler for the exception. Any associated finally clause of a
try block encountered along the search path is executed. If no handler is found, then the
exception is dealt with by the default exception handler at the top level. If a handler is
found, normal execution resumes after the code in its catch clause has been executed,
barring any rethrowing of an exception.
In Example 6.17, an exception is thrown using a throw statement at (17). This exception
is propagated to the main() method, where it is caught and handled by the catch
clause at (3). Note that the finally clauses at (6) and (14) are executed. Execution
continues normally at (7).

WOW! eBook
www.wowebook.org

Example 6.17

Throwing Exceptions

Click here to view code image
public class Average7 {
public static void main(String[] args) {
try {
printAverage(100, 0);
} catch (ArithmeticException ae) {
ae.printStackTrace();
System.out.println(“Exception handled in main().”);
} finally {
System.out.println(“Finally in main().”);
}
System.out.println(“Exit main().”);
}
public static void printAverage(int totalSum, int totalNumber) {
try {
int average = computeAverage(totalSum, totalNumber);
System.out.println(“Average = ” +
totalSum + ” / ” + totalNumber + ” = ” + average);
} catch (IllegalArgumentException iae) {
iae.printStackTrace();
System.out.println(“Exception handled in printAverage().”);
} finally {
System.out.println(“Finally in printAverage().”);
}
System.out.println(“Exit printAverage().”);
}
public static int computeAverage(int sum, int number) {
System.out.println(“Computing average.”);
if (number == 0)
throw new ArithmeticException(“Integer division by 0”);
return sum/number;
}

//
//
//
//
//

(1)
(2)
(3)
(4)
(5)

// (6)
// (7)

// (8)
// (9)
// (10)
// (11)
// (12)
// (13)
// (14)
// (15)

// (16)
// (17)
// (18)

}

Output from the program:
Click here to view code image
Computing average.
Finally in printAverage().
java.lang.ArithmeticException: Integer division by 0
at Average7.computeAverage(Average7.java:33)
at Average7.printAverage(Average7.java:18)
at Average7.main(Average7.java:6)
Exception handled in main().
Finally in main().
Exit main().

6.9 The

Clause

A throws clause can be specified in a method or a constructor header to declare any
checked exceptions that can be thrown by a statement in the body of a method or a
constructor. It is declared immediately preceding the body of the method or the
constructor.
WOW! eBook
www.wowebook.org

Click here to view code image
… throws ExceptionType1, ExceptionType2,…, ExceptionTypen { … }

Each ExceptionTypei is an exception type, although usually only checked exceptions are
specified. The compiler enforces that if a checked exception can be the result of executing
a method or a constructor, then either the exception type of this exception or a supertype
of its exception type is specified in the throws clause of the method or the constructor.
The throws clause can specify unchecked exceptions, but this is seldom done and the
compiler does not enforce any restrictions on their usage.
The throws clause is part of the contract that a method or a constructor offers to its
clients. The throws clause can specify any number of exception types, even those that
are not thrown by the method or the constructor. The compiler simply ensures that any
checked exception that can actually be thrown in the method or constructor body is
covered by the throws clause. Of course, the clients cannot ignore the checked
exceptions in the throws clause.
In a method or a constructor, a checked exception can be thrown directly by a throw
statement, or indirectly by calling other methods or constructors that can throw a checked
exception. If a checked exception is thrown, it must be handled in one of three ways:
• By using a try block and catching the exception in a handler and dealing with it
• By using a try block and catching the exception in a handler, but throwing another
exception that is either unchecked or declared in its throws clause
• By explicitly allowing propagation of the exception to its caller by declaring it in the
throws clause of its header
This mechanism (also known as catch-or-declare) ensures that a checked exception will
be dealt with, regardless of the path of execution. This aids development of robust
programs, as allowance can be made for many contingencies. Native methods can also
declare checked exceptions in their throws clause, but the compiler is not able to check
them for consistency.
In Example 6.18, a new checked exception is defined, where the checked exception class
IntegerDivisionByZero extends the Exception class. The method main()
calls the method printAverage() in a try block at (1). In the if statement at (9), the
method computeAverage() throws the checked exception
IntegerDivisionByZero. Neither the computeAverage() method nor the
printAverage() method catches the exception, but instead throws it to the caller, as
declared in the throws clauses in their headers at (6) and (8). The exception propagates
to the main() method. Since the printAverage() method was called from the
context of the try block at (1) in the main() method, the exception is successfully
caught by its catch clause at (3). The exception is handled and the finally clause at
(4) executed, with normal execution resuming from (5). If the method main() did not
catch the exception, it would have to declare this exception in a throws clause. In that
case, the exception would end up being handled by the default exception handler.
WOW! eBook
www.wowebook.org

Example 6.18

The throws Clause

Click here to view code image
// File: IntegerDivisionByZero.java
public class IntegerDivisionByZero extends Exception {
IntegerDivisionByZero(String str) { super(str); }
}
// File: Average8.java
public class Average8 {
public static void main(String[] args) {
try {
printAverage(100, 0);
} catch (IntegerDivisionByZero idbz) {
idbz.printStackTrace();
System.out.println(“Exception handled in main().”);
} finally {
System.out.println(“Finally done in main().”);
}
System.out.println(“Exit main().”);
}
public static void printAverage(int totalSum, int totalNumber)
throws IntegerDivisionByZero {
int average = computeAverage(totalSum, totalNumber);
System.out.println(“Average = ” +
totalSum + ” / ” + totalNumber + ” = ” + average);
System.out.println(“Exit printAverage().”);
}

// (1)
// (2)
// (3)

// (4)

// (5)

// (6)

// (7)

public static int computeAverage(int sum, int number)
throws IntegerDivisionByZero {
// (8)
System.out.println(“Computing average.”);
if (number == 0)
// (9)
throw new IntegerDivisionByZero(“Integer Division By Zero”);
return sum/number;
// (10)
}
}

Output from the program:
Click here to view code image
Computing average.
IntegerDivisionByZero: Integer Division By Zero
at Average8.computeAverage(Average8.java:27)
at Average8.printAverage(Average8.java:17)
at Average8.main(Average8.java:5)
Exception handled in main().
Finally done in main().
Exit main().

As mentioned earlier, the exception type specified in the throws clause can be a
superclass of the actual exceptions thrown; that is, the exceptions thrown must be
assignable to the type of the exceptions specified in the throws clause. If a method or a
constructor can throw a checked exception, then the throws clause must declare its
exception type or a supertype of its exception type; otherwise, a compile-time error will
occur. In the printAverage() method, the method header could specify the superclass
WOW! eBook
www.wowebook.org

Exception of the subclass IntegerDivisionByZero in the throws clause. This
would also entail that the main() method either catch an Exception or declare it in a
throws clause.
Click here to view code image
public static void main(String[] args) throws Exception {
/* … */
}
public static void printAverage(int totalSum, int totalNumber) throws
Exception {
/* … */
}

It is generally considered bad programming style to specify exception superclasses in the
throws clause of the header when the actual exceptions thrown are instances of their
subclasses. It is also recommended to use the @throws tag in a Javadoc comment to
document the checked exceptions that a method or a constructor can throw, together with
any unchecked exceptions that might also be relevant to catch.

Overriding the

Clause

A subclass can override a method defined in its superclass by providing a new
implementation (§7.2, p. 268). What happens when a superclass method with a list of
exceptions in its throws clause is overridden in a subclass? The method declaration in
the subclass need not specify a throws clause if it does not throw any checked
exceptions, and if it does, it can specify only checked exception classes that are already in
the throws clause of the superclass method, or that are subclasses of the checked
exceptions in the throws clause of the superclass method. As a consequence, an
overriding method cannot allow more checked exceptions in its throws clause than the
superclass method does. Allowing more checked exceptions in the overriding method
would create problems for clients who already deal with the exceptions specified in the
superclass method. Such clients would be ill prepared if an object of the subclass threw a
checked exception they were not prepared for. However, there are no restrictions on
specifying unchecked exceptions in the throws clause of the overriding method. The
preceding discussion also applies to methods from an interface that a class implements, as
these methods are overridden by any class implementing the interface.
In the following code, the method superclassMethodX in superclass A is overridden
in subclass B. The throws clause of the method in subclass B at (2) specifies a subset of
the checked exceptions specified in the throws clause at (1) and adds the more specific
subclass exception, SubFirstException, of the superclass exception, FirstException, specified in the throws clause at (1).
Click here to view code image
// New exception classes:
class FirstException
extends
class SecondException
extends
class ThirdException
extends
class SubFirstException extends

Exception { }
Exception { }
Exception { }
FirstException { }

WOW! eBook
www.wowebook.org

// Superclass
class A {
// …
protected void superclassMethodX()
throws FirstException, SecondException, ThirdException {/* … */}
//
(1)
// …
}
// Subclass
class B extends A {
// …
@Override protected void superclassMethodX()
throws FirstException, ThirdException, SubFirstException { /* … */ } //
(2)
// …
}

6.10 Advantages of Exception Handling
Robustness refers to the ability of a software system to respond to errors during execution.
A system should respond to unexpected situations at runtime in a responsible way.
Applications that provide the user with frequent cryptic messages with error codes or that
repeatedly give the user the silent treatment when something goes wrong can hardly be
considered robust.
The exception handling mechanism in Java offers the following advantages that facilitate
developing robust applications in Java:
• Separation of Exception Handling Code
The code for handling error situations can be separated from the code for the
program logic by using the exception handling constructs provided by the language.
Code that can result in error situations is confined in the try block, and their
handling in the catch clause.
• Transparent Exception Propagation
Propagation of a checked exception in the JVM stack cannot be ignored by an active
method. The method must comply with the catch-or-declare requirement: either
catch and handle the exception, or propagate it by declaring it in the method’s
throws clause. Error situations causing exception propagation are thus always
detected, and can be caught and remedied.
• Exception Categorization and Specialization
The exception and error classes in the Java SE platform API are organized in an
inheritance hierarchy (Figure 6.9, p. 234). Classes higher up in this hierarchy
represent categories of exceptions and errors (Exception,
RuntimeException, IO-Exception, Error), whereas classes lower in this
hierarchy represent more specific exceptions and errors
(NullPointerException, FileNotFoundException,
AssertionError). The try-catch construct allows flexibility in catching and
handling exceptions. A catch clause can specify an exception category for coarsegrained exception handling, as the exception category class will subsume its more
WOW! eBook
www.wowebook.org

specific exception subclasses, or it can specify a more specific exception class for
fine-grained exception handling. Best practice dictates that fine-grained exception
handling be used.

Review Questions
6.16 Which digits, and in which order, will be printed when the following program is
run?
Click here to view code image
public class DemoClass {
public static void main(String[] args) {
int k=0;
try {
int i = 5/k;
} catch (ArithmeticException e) {
System.out.println(“1”);
} catch (RuntimeException e) {
System.out.println(“2”);
return;
} catch (Exception e) {
System.out.println(“3”);
} finally {
System.out.println(“4”);
}
System.out.println(“5”);
}
}

Select the one correct answer.
(a) The program will only print 5.
(b) The program will only print 1 and 4, in that order.
(c) The program will only print 1, 2, and 4, in that order.
(d) The program will only print 1, 4, and 5, in that order.
(e) The program will only print 1, 2, 4, and 5, in that order.
(f) The program will only print 3 and 5, in that order.
6.17 Given the following program, which statements are true?
Click here to view code image
public class Exceptions {
public static void main(String[] args) {
try {
if (args.length == 0) return;
System.out.println(args[0]);
} finally {
System.out.println(“The end”);
}
}
}

Select the two correct answers.
WOW! eBook
www.wowebook.org

(a) If run with no arguments, the program will produce no output.
(b) If run with no arguments, the program will print The end.
(c) The program will throw an ArrayIndexOutOfBoundsException.
(d) If run with one argument, the program will simply print the given argument.
(e) If run with one argument, the program will print the given argument followed
by "The end".
6.18 Which of the following statements are true?
Select the two correct answers.
(a) If an exception is not caught in a method, the method will terminate and normal
execution will resume.
(b) An overriding method must declare that it throws the same exception classes as
the method it overrides.
(c) The main() method of a program can declare that it throws checked
exceptions.
(d) A method declaring that it throws an exception of a certain class may throw
instances of any subclass of that exception class.
(e) finally clauses are executed if, and only if, an exception gets thrown while
inside the corresponding try block.
6.19 Which digits, and in which order, will be printed when the following program is
run?
Click here to view code image
public class RQ6A19 {
public static void main(String[] args) throws InterruptedException {
try {
throwIt();
System.out.println(“1”);
} finally {
System.out.println(“2”);
}
System.out.println(“3”);
}
// InterruptedException is a direct subclass of Exception.
static void throwIt() throws InterruptedException {
throw new InterruptedException(“Time to go home.”);
}
}

Select the one correct answer.
(a) The program will print 2 and throw InterruptedException.
(b) The program will print 1 and 2, in that order.
(c) The program will print 1, 2, and 3, in that order.
WOW! eBook
www.wowebook.org

(d) The program will print 2 and 3, in that order.
(e) The program will print 3 and 2, in that order.
(f) The program will print 1 and 3, in that order.
6.20 What is wrong with the following code?
Click here to view code image
public class RQ6A20 {
public static void main(String[] args) throws A {
try {
action();
} finally {
System.out.println(“Done.”);
} catch (A e) {
throw e;
}
}
public static void action() throws B {
throw new B();
}
}
class A extends Throwable {}
class B extends A {}

Select the one correct answer.
(a) The main() method must declare that it throws B.
(b) The finally clause must follow the catch clause in the main() method.
(c) The catch clause in the main() method must declare that it catches B rather
than A.
(d) A single try block cannot be followed by both catch and finally clauses.
(e) The declaration of class A is illegal.
6.21 Which throws clause should be inserted at (1) for the overriding method
compute() in the following code so that the code will compile without errors?
Click here to view code image
class A {
// InterruptedException is a direct subclass of Exception.
void compute() throws ArithmeticException, InterruptedException {
div(5, 5);
}
int div(int i, int j) throws ArithmeticException {
return i/j;
}
}
public class Client extends A {
void compute() /* (1) INSERT throws CLAUSE HERE. */ {
try {
div(5, 0);
WOW! eBook
www.wowebook.org

} catch (ArithmeticException e) {
return;
}
throw new RuntimeException(“ArithmeticException was expected.”);
}
}

Select the one correct answer.
(a) No throws clause is necessary.
(b) throws ArithmeticException
(c) throws InterruptedException
(d) throws RuntimeException
(e) throws ArithmeticException, InterruptedException

Chapter Summary
The following information was covered in this chapter:
• The selection statements: if, if-else, switch
• The iteration statements: for(;;), for(:), while, do-while
• The transfer statements: break, continue, return
• Exception handling and exception classes in the core API
• Defining customized exception types
• The try-catch-finally construct and control flow paths through the construct
• Using multiple catch clauses with the try statement
• Throwing exceptions programmatically with the throw statement
• Using the throws clause to specify checked exceptions

Programming Exercises
6.1 Create different versions of a program that finds all the primes smaller than 100.
Create one version that uses only the for(;;) loop (i.e., no while or dowhile). Create another version that uses only the while loop.
6.2 Here is a skeleton of a system for simulating a nuclear power plant. Implement the
methods in the class named Control. Modify the method declarations if
necessary. The Javadoc comments for each method give a description of what the
implementation should do. Some of the methods in the other classes have
unspecified implementations. Assume that these methods have been properly
implemented and provide hooks to the rest of the system.
Click here to view code image
package energy;
WOW! eBook
www.wowebook.org

/** A PowerPlant with a reactor core. */
public class PowerPlant {
/** Each power plant has a reactor core.
This field has package accessibility so that the Control class,
defined in the same package, can access it. */
final Reactor core;
/** Initializes the power plant, creates a reactor core. */
public PowerPlant() {
core = new Reactor();
}
/** Sounds the alarm to evacuate the power plant. */
public void soundEvacuateAlarm() {
// … implementation unspecified …
}
/** @return the level of reactor output that is most desirable at this
time.
(Units are unspecified.) */
public int getOptimalThroughput() {
// … implementation unspecified …
return 0;
}
/** The main entry point of the program: sets up a PowerPlant object
and a Control object and lets the Control object run the power plant.
*/
public static void main(String[] args) {
PowerPlant plant = new PowerPlant();
Control ctrl = new Control(plant);
ctrl.runSystem();
}
}
//______________________________________________________________________________
/** A reactor core that has a throughput that can be either decreased or
increased. */
class Reactor {
/** @return the current throughput of the reactor. (Units are unspecified.)
*/
public int getThroughput() {
// … implementation unspecified …
return 0;
}
/** @return true if the reactor status is critical, false otherwise. */
public boolean isCritical() {
// … implementation unspecified …
return false;
}
/** Asks the reactor to increase throughput. */
void increaseThroughput() throws ReactorCritical {
// … implementation unspecified …
}
/** Asks the reactor to decrease throughput. */
void decreaseThroughput() {
// … implementation unspecified …
}
WOW! eBook
www.wowebook.org

}
//______________________________________________________________________________
/** This exception class should be used to report that the reactor status is
critical. */
class ReactorCritical extends Exception {}
//______________________________________________________________________________
/** A controller that will manage the power plant to make sure that the
reactor runs with optimal throughput. */
class Control {
private final PowerPlant thePlant;
static final int TOLERANCE = 10;
/** @param p the power plant to control */
public Control(PowerPlant p) {
thePlant = p;
}
/** Runs the power plant by continuously monitoring the
optimal throughput and the actual throughput of the reactor.
If the throughputs differ by more than 10 units (i.e. tolerance),
adjust the reactor throughput.
If the reactor goes critical, the evacuate alarm is
sounded and the reactor is shut down.
The runSystem() method calls the methods needAdjustment(),
adjustThroughput(), and shutdown(). */
public void runSystem() {
// … provide implementation here …
}
/** Reports whether the throughput of the reactor needs adjusting.
This method should also monitor and report if the reactor goes
critical.
@param target the desired throughput.
@return true if the optimal and actual throughput values differ by
more than 10 units. */
public boolean needAdjustment(int target) {
// … provide implementation here …
return true;
}
/** Adjusts the throughput of the reactor by calling increaseThroughput()
and decreaseThroughput() methods until the actual throughput is within
10 units of the target throughput.
@param target the desired throughput. */
public void adjustThroughput(int target) {
// … provide implementation here …
}
/** Shuts down the reactor by lowering the throughput to 0. */
public void shutdown() {
// … provide implementation here …
}
}

WOW! eBook
www.wowebook.org

7. Object-Oriented Programming

7.1 Single Implementation Inheritance
Inheritance is one of the fundamental mechanisms for code reuse in object-oriented
programming (OOP). It allows new classes to be derived from existing ones. The new
class (also called a subclass, subtype, derived class, or child class) can inherit members
from the old class (also called a superclass, supertype, base class, or parent class). The
subclass can add new behavior and properties and, under certain circumstances, modify its
inherited behavior.
In Java, implementation inheritance (also known as class inheritance) is achieved by
extending classes (i.e., adding new fields and methods) and modifying inherited members
(§7.2, p. 268). Inheritance of members is closely tied to their declared accessibility. If a
superclass member is accessible by its simple name in the subclass (without the use of any
extra syntax like super), that member is considered inherited. Conversely, private,
overridden, and hidden members of the superclass are not inherited. Inheritance should not
WOW! eBook
www.wowebook.org

be confused with the existence of such members in the state of a subclass object (Example
7.1).
A subclass specifies the name of its superclass in the subclass header using the extends
clause.
Click here to view code image
class TubeLight extends Light { … }

// TubeLight is a subclass of Light.

The subclass specifies only the additional new and modified members in its class body.
The rest of its declaration is made up of its inherited members. If no extends clause is
specified in the header of a class declaration, the class implicitly inherits from the
java.lang.Object class (§8.2, p. 342). This implicit inheritance is assumed in the
declaration of the Light class at (1) in Example 7.1. Also in Example 7.1, the subclass
TubeLight at (2) explicitly uses the extends clause and specifies only members other
than those that it already inherits from the superclass Light (which, in turn, inherits from
the Object class). Members of the superclass Light, which are accessible by their
simple names in the subclass TubeLight, are inherited by the subclass, as evident from
the output in Example 7.1.
Private members of the superclass are not inherited by the subclass and can be accessed
only indirectly. The private field indicator of the superclass Light is not inherited,
but exists in the subclass object and is indirectly accessible through public methods.
Using appropriate accessibility modifiers, the superclass can limit which members can be
accessed directly and, therefore, inherited by its subclasses (§4.7, p. 123). As shown in
Example 7.1, the subclass can use the inherited members as if they were declared in its
own class body. This is not the case for members that are declared as private in the
superclass. Members that have package accessibility in the superclass are also not
inherited by subclasses in other packages, as these members are accessible by their simple
names only in subclasses within the same package as the superclass.
Since constructors (§7.5, p. 282) are not members of a class, they are not inherited by a
subclass.
Example 7.1

Extending Classes: Inheritance and Accessibility

Click here to view code image
// File: Utility.java
class Light {
// Instance fields:
int
noOfWatts;
private
boolean indicator;
protected String location;
// Static field:
private static int counter;

// (1)
// Wattage
// On or off
// Placement

// Number of Light objects created

// No-argument constructor:
Light() {
noOfWatts = 50;
indicator = true;
location = “X”;
WOW! eBook
www.wowebook.org

counter++;
}
// Instance methods:
public void
switchOn() { indicator = true; }
public void
switchOff() { indicator = false; }
public boolean isOn()
{ return indicator; }
private void
printLocation() {
System.out.println(“Location: ” + location);
}
// Static methods:
public static void writeCount() {
System.out.println(“Number of lights: ” + counter);
}
//…
}
//______________________________________________________________________________
class TubeLight extends Light {
// (2) Subclass uses the extends
clause.
// Instance fields:
private int tubeLength = 54;
private int colorNo
= 10;
// Instance methods:
public int getTubeLength() { return tubeLength; }
public void printInfo() {
System.out.println(“From the subclass:”);
System.out.println(“Tube length: “ + tubeLength);
System.out.println(“Color number: ” + colorNo);
System.out.println(“Tube length: “ + getTubeLength());
System.out.println();
System.out.println(“From the superclass:”);
System.out.println(“Wattage: “
+ noOfWatts);
// Inherited.
// System.out.println(“Indicator: “
+ indicator);
// Not inherited.
System.out.println(“Location: “
+ location);
// Inherited.
// System.out.println(“Counter: “
+ counter);
// Not inherited.
switchOn();
// Inherited
switchOff();
// Inherited
System.out.println(“Indicator: “
+ isOn());
// Inherited.
// printLocation();
// Not inherited.
writeCount();
// Inherited.
}
// …
}
//______________________________________________________________________________
public class Utility {
// (3)
public static void main(String[] args) {
new TubeLight().printInfo();
}
}

Output from the program:
From the subclass:
Tube length: 54
Color number: 10
Tube length: 54
From the superclass:
Wattage: 50
Location: X
WOW! eBook
www.wowebook.org

Indicator: false
Number of lights: 1

In Java, a class can extend only one class; that is, it can have only one immediate
superclass. This kind of inheritance is sometimes called single or linear implementation
inheritance. The name is appropriate, as the subclass inherits the implementations of its
superclass members. The inheritance relationship can be depicted as an inheritance
hierarchy (also called a class hierarchy). Classes higher up in the hierarchy are more
generalized (often called broader), as they abstract the class behavior. Classes lower down
in the hierarchy are more specialized (often called narrower), as they customize the
inherited behavior by additional properties and behavior. Figure 7.1 illustrates the
inheritance relationship between the class Light, which represents the more general
abstraction, and its more specialized subclasses. The java.lang.Object class is
always at the top (the root) of any Java inheritance hierarchy, as all classes, with the
exception of the Object class itself, inherit (either directly or indirectly) from this class.

Figure 7.1

Inheritance Hierarchy

WOW! eBook
www.wowebook.org

Relationships: is-a and has-a
Inheritance defines the relationship is-a (also called the superclass–subclass relationship)
between a superclass and its subclasses. Thus, an object of a subclass is-a superclass
object, and can be used wherever an object of the superclass can be used. This criterion is
often employed as a litmus test for choosing inheritance in object-oriented design. It has
particular consequences for how objects can be used. An object of the TubeLight class
is-an object of the superclass Light. Referring to Figure 7.1, an object of the
TubeLight class can be used wherever an object of the superclass Light can be used.
The inheritance relationship is transitive: If class B extends class A and class C extends
class B, then class C will also inherit from class A via class B. An object of the
SpotLightBulb class is-an object of the class Light. The is-a relationship does not
hold between peer classes: An object of the LightBulb class is not an object of the class
TubeLight, and vice versa.
Whereas inheritance defines the relationship is-a between a superclass and its subclasses,
aggregation defines the relationship has-a (also called the whole–part relationship)
between an instance of a class and its constituents (also called parts). Aggregation
comprises the usage of objects. An instance of class Light has (or uses) the following
parts: a field to store its wattage (noOfWatts), a field to store whether it is on or off
(indicator), and a String object to store its location (denoted by the field reference
location). In Java, a composite object cannot contain other objects. It can store only
reference values of its constituent objects in its fields. This relationship defines an
aggregation hierarchy (also called object hierarchy) that embodies the has a relationship.
As explained in §1.7, p. 12, constituent objects can be shared between objects. If their
lifetimes are dependent on the lifetime of the composite object, then this relationship is
called composition, and implies strong ownership of the parts by the composite object.
Inheritance and aggregation are compared in §7.13, p. 331.

The Supertype–Subtype Relationship
A class defines a reference type, a data type whose objects can be accessed only by
references. Therefore the inheritance hierarchy can be regarded as a type hierarchy,
embodying the supertype–subtype relationship between reference types. In the context of
Java, the supertype–subtype relationship implies that the reference value of a subtype
object can be assigned to a supertype reference, because a subtype object can be
substituted for a supertype object. This assignment involves a widening reference
conversion (§5.1, p. 145), as references are assigned up the inheritance hierarchy. Using
the reference types in Example 7.1, the following code assigns the reference value of an
object of the subtype TubeLight to the reference light of the supertype Light:
Click here to view code image
Light light = new TubeLight();
conversion

// (1) widening reference

An implicit widening conversion takes place under assignment, as the reference value of a
narrower type (subtype TubeLight) object is being assigned to a reference of broader
type (supertype Light). We can now use the reference light to invoke those methods
WOW! eBook
www.wowebook.org

on the subtype object that are inherited from the supertype Light:
Click here to view code image
light.switchOn();

// (2)

Note that the compiler knows about only the declared type (static type) of the reference
light, which is Light, and ensures that only methods from this type can be called
using the reference light. However, at runtime, the reference light will refer to an
object of the subtype TubeLight when the call to the method switchOn() is
executed. It is the type of the object that the reference refers to at runtime that determines
which method is executed. The subtype object inherits the switchOn() method from its
supertype Light, so this method is executed. The type of the object that the reference
refers to at runtime is often called the dynamic type of the reference.
One might be tempted to invoke methods exclusive to the TubeLight subtype via the
supertype reference light:
Click here to view code image
light.getTubeLength();

// (3) Not OK.

This code will not work, as the compiler does not know which object the reference light
will denote at runtime; it merely knows the declared type of the reference. As the
declaration of the class Light does not have a method called getTubeLength(), this
method call at (3) results in a compile-time error. As we shall see later in this chapter,
eliciting subtype-specific behavior using a supertype reference requires a narrowing
reference conversion with an explicit cast (§7.11, p. 320).
The rest of this chapter elaborates on various aspects of OOP. Understanding them is
fundamental in understanding the consequences of the subtype–supertype relationship.

7.2 Overriding Methods
Instance Method Overriding
Under certain circumstances, a subclass can override instance methods that it inherits from
its superclass. Overriding such a method allows the subclass to provide its own
implementation of the method. The overridden method in the superclass is not inherited by
the subclass. When the method is invoked on an object of the subclass, it is the method
implementation in the subclass that is executed. The new method in the subclass must
abide by the following rules of method overriding:
• The new method definition in the subclass must have the same method signature. In
other words, the method name, and the types and the number of parameters,
including their order, must be the same as in the overridden method of the
superclass.
Whether parameters in the overriding method should be final is at the discretion
of the subclass (§3.7, p. 86). A method’s signature does not comprise the final
modifier of parameters, only their types and order.
• The return type of the overriding method can be a subtype of the return type of the
WOW! eBook
www.wowebook.org

overridden method (called covariant return, p. 273).
• The new method definition cannot narrow the accessibility of the method, but it can
widen it (§4.7, p. 123).
• The new method definition can throw either all or none, or a subset of the checked
exceptions (including their subclasses) that are specified in the throws clause of
the overridden method in the superclass (§6.9, p. 253).
These requirements also apply to interfaces, where a subinterface can override abstract
and default method declarations from its superinterfaces (§7.6, p. 290).
Example 7.2 illustrates overriding, overloading, and hiding of members in a class. Figure
7.2 gives an overview of the two main classes in Example 7.2. The new definition of the
energyCost() method at (7) in the subclass TubeLight has the same signature and
the same return type as the method at (2) in the superclass Light. The new definition
specifies a subset of the exceptions (ZeroHoursException) thrown by the overridden
method (the exception class InvalidHoursException is a superclass of
NegativeHoursException and ZeroHoursException). The new definition also
widens the accessibility (public) from what it was in the overridden definition
(protected). The overriding method declares the parameter to be final, but this has
no bearing in overriding the method.

Figure 7.2

Inheritance Hierarchy for Example 7.2 and Example 7.3

The astute reader will have noticed the @Override annotation preceding the method
definition at (7). The compiler will now report an error if the method definition at (7) does
not override an inherited method. The annotation helps to ensure that the method
definition overrides the inherited method, rather than overloading another method silently.
WOW! eBook
www.wowebook.org

Invocation of the method energyCost() on an object of subclass TubeLight using
references of the subclass and the superclass at (15) and (16) results in the new definition
at (7) being executed, since both references are aliases of the TubeLight object created
at (12).
Click here to view code image
tubeLight.energyCost(50);
light1.energyCost(50);

// (15) Invokes method at (7).
// (16) Invokes method at (7).

Not surprisingly, the invocation of the method energyCost() on an object of
superclass Light, using a reference of the superclass at (17), results in the overridden
definition at (2) being executed:
Click here to view code image
light2.energyCost(50);
Example 7.2

// (17) Invokes method at (2).

Overriding, Overloading, and Hiding

Click here to view code image
// File: Client2.java
// Exceptions
class InvalidHoursException extends Exception {}
class NegativeHoursException extends InvalidHoursException {}
class ZeroHoursException extends InvalidHoursException {}
class Light {
protected String lightType = “Generic Light”;

// (1) Instance field

protected double energyCost(int noOfHours)
// (2) Instance method
throws InvalidHoursException {
System.out.print(“>> Light.energyCost(int): “);
if (noOfHours < 0)
throw new NegativeHoursException();
double cost = 00.20 * noOfHours;
System.out.println(“Energy cost for ” + lightType + “: ” + cost);
return cost;
}
public Light makeInstance() {
// (3) Instance method
System.out.print(“>> Light.makeInstance(): “);
return new Light();
}
public void showSign() {
System.out.print(“>> Light.showSign(): “);
System.out.println(“Let there be light!”);
}

// (4) Instance method

public static void printLightType() {
// (5) Static method
System.out.print(“>> Static Light.printLightType(): “);
System.out.println(“Generic Light”);
}
}
//______________________________________________________________________________
class TubeLight extends Light {
public static String lightType = “Tube Light”;
WOW! eBook
www.wowebook.org

// (6) Hiding field at (1).

@Override
public double energyCost(final int noOfHours)
// (7) Overriding instance
throws ZeroHoursException {
//
method at (2).
System.out.print(“>> TubeLight.energyCost(int): “);
if (noOfHours == 0)
throw new ZeroHoursException();
double cost = 00.10 * noOfHours;
System.out.println(“Energy cost for ” + lightType + “: ” + cost);
return cost;
}
public double energyCost() {
// (8) Overloading method at (7).
System.out.print(“>> TubeLight.energyCost(): “);
double flatrate = 20.00;
System.out.println(“Energy cost for ” + lightType + “: ” + flatrate);
return flatrate;
}
@Override
public TubeLight makeInstance() {
// (9) Overriding instance method at
(3).
System.out.print(“>> TubeLight.makeInstance(): “);
return new TubeLight();
}
public static void printLightType() { // (10) Hiding static method at (5).
System.out.print(“>> Static TubeLight.printLightType(): “);
System.out.println(lightType);
}
}
//______________________________________________________________________________
public class Client2 {
public static void main(String[] args)
// (11)
throws InvalidHoursException {
TubeLight tubeLight = new TubeLight();
Light
light1
= tubeLight;
Light
light2
= new Light();

// (12)
// (13) Aliases.
// (14)

System.out.println(“Invoke overridden instance method:”);
tubeLight.energyCost(50);
// (15) Invokes method at (7).
light1.energyCost(50);
// (16) Invokes method at (7).
light2.energyCost(50);
// (17) Invokes method at (2).
System.out.println(
”\nInvoke overridden instance method with covariant return:”);
System.out.println(
light2.makeInstance().getClass());
// (18) Invokes method at (3).
System.out.println(
tubeLight.makeInstance().getClass()); // (19) Invokes method at (9).
System.out.println(“\nAccess hidden field:”);
System.out.println(tubeLight.lightType); // (20) Accesses field at (6).
System.out.println(light1.lightType);
// (21) Accesses field at (1).
System.out.println(light2.lightType);
// (22) Accesses field at (1).
System.out.println(“\nInvoke hidden static method:”);
tubeLight.printLightType();
// (23) Invokes method at
(10).
light1.printLightType();
// (24) Invokes method at (5).
light2.printLightType();
// (25) Invokes method at (5).

WOW! eBook
www.wowebook.org

System.out.println(“\nInvoke overloaded method:”);
tubeLight.energyCost();
// (26) Invokes method at (8).
}
}

Output from the program:
Click here to view code image
Invoke overridden instance method:
>> TubeLight.energyCost(int): Energy cost for Tube Light: 5.0
>> TubeLight.energyCost(int): Energy cost for Tube Light: 5.0
>> Light.energyCost(int): Energy cost for Generic Light: 10.0
Invoke overridden instance method with covariant return:
>> Light.makeInstance(): class Light
>> TubeLight.makeInstance(): class TubeLight
Access hidden field:
Tube Light
Generic Light
Generic Light
Invoke hidden static method:
>> Static TubeLight.printLightType(): Tube Light
>> Static Light.printLightType(): Generic Light
>> Static Light.printLightType(): Generic Light
Invoke overloaded method:
>> TubeLight.energyCost(): Energy cost for Tube Light: 20.0

Here are a few more facts to note about overriding. First, a subclass must use the keyword
super to invoke an overridden method in the superclass (p. 276).
Second, a final method cannot be overridden, because the modifier final prevents
method overriding. An attempt to override a final method will result in a compile-time
error. An abstract method, in contrast, requires the non-abstract subclasses to override
the method, so as to provide an implementation.
Third, the accessibility modifier private for a method means that the method is not
accessible outside the class in which it is defined; therefore, a subclass cannot override it.
However, a subclass can give its own definition of such a method, which may have the
same signature as the method in its superclass.
Fourth, a subclass within the same package as the superclass can override any non-final
and non-private methods declared in the superclass. However, a subclass in a different
package can override only the non-final methods that are declared as either public or
protected in the superclass.
Fifth, an instance method in a subclass cannot override a static method in the
superclass. The compiler will flag such an attempt as an error. A static method is classspecific and not part of any object, while overriding methods are invoked on behalf of
objects of the subclass. However, a static method in a subclass can hide a static method
in the superclass, as we shall see (p. 275). Constructors, since they are not methods,
cannot be overridden.
WOW! eBook
www.wowebook.org

Covariant

in Overriding Methods

In Example 7.2, the definition of the method makeInstance() at (9) overrides the
method definition at (3). Note that the method signatures are the same, but the return type
at (9) is a subtype of the return type at (3). The method at (9) returns an object of the
subtype TubeLight, whereas the method at (3) returns an object of the supertype
Light. This is an example of covariant return.
Depending on whether we call the method makeInstance() on an object of the
subtype TubeLight or an object of the supertype Light, the respective method
definition will be executed. The code at (18) and (19) illustrates which object is returned
by the method, depending on which method definition is executed.
Note that covariant return applies only to reference types, not to primitive types. For
example, changing the return type of the energyCost() method at (7) to float will
result in a compile-time error. There is no supertype–subtype relationship between
primitive types.

Overriding versus Overloading
Method overriding should not be confused with method overloading (§3.2, p. 52).
Method overriding always requires the same method signature (name and parameter types)
and the same or covariant return types. Overloading occurs when the method names are
the same, but the parameter lists differ. Therefore, to overload methods, the parameters
must differ in either type, order, or number. As the return type is not a part of the method
signature, just having different return types is not enough to overload methods.
Only non-final instance methods in the superclass that are directly accessible from the
subclass using their simple name can be overridden. Both instance and static methods can
be overloaded in the class they are defined in or in a subclass of their class.
Invoking an overridden method in the superclass from a subclass requires a special syntax
(e.g., the keyword super). This is not necessary for invoking an overloaded method in
the superclass from a subclass. If the right kinds of arguments are passed in the method
call occurring in the subclass, the overloaded method in the superclass will be invoked. In
Example 7.2, the method energyCost() at (2) in class Light is overridden in class
TubeLight at (7) and overloaded at (8). When invoked at (26), the overloaded
definition at (8) is executed.
For overloaded methods, which method implementation will be executed at runtime is
determined at compile time (§7.10, p. 316). In contrast, for overridden methods, the
method implementation to be executed is determined at runtime (§7.12, p. 329). Table 7.1
provides a comparison between overriding and overloading.

WOW! eBook
www.wowebook.org

Table 7.1

Overriding versus Overloading

7.3 Hiding Members
Field Hiding
A subclass cannot override inherited fields of the superclass, but it can hide them. The
subclass can define fields with the same name as in the superclass. If this is the case, the
fields in the superclass cannot be accessed in the subclass by their simple names;
therefore, they are not inherited by the subclass. A hidden static field can always be
invoked by using the superclass name in the subclass declaration. Additionally, the
keyword super can be used in non-static code in the subclass declaration to access
hidden static fields (§7.4, p. 276).
The following distinction between invoking instance methods on an object and accessing
fields of an object must be noted. When an instance method is invoked on an object using
a reference, it is the dynamic type of the reference (i.e., the type of the current object
denoted by the reference at runtime), not the declared type of the reference, that
determines which method implementation will be executed. In Example 7.2 at (15), (16),
WOW! eBook
www.wowebook.org

and (17), this is evident from invoking the overridden method energyCost(): The
method from the class corresponding to the current object is executed, regardless of the
declared reference type. When a field of an object is accessed using a reference, it is the
declared type of the reference, not the type of the current object denoted by the reference,
that determines which field will actually be accessed. In Example 7.2 at (20), (21), and
(22), this is evident from accessing the hidden field lightType: The field accessed is
the one declared in the class corresponding to the declared reference type, regardless of
the object denoted by the reference at runtime.
In contrast to method overriding, where an instance method cannot override a static
method, there are no such restrictions on the hiding of fields. The field lightType is
static in the subclass, but not in the superclass. The declared type of the fields need not
be the same either—only the field name matters in the hiding of fields.

Static Method Hiding
A static method in a subclass cannot override an instance method from the superclass, but
it can hide a static method from the superclass if the exact requirements for overriding
instance methods are fulfilled (§7.2, p. 268). A hidden superclass static method is not
inherited. The compiler will flag the code as containing an error if the signatures are the
same, but the other requirements regarding return type, throws clause, and accessibility
are not met. If the signatures are different, the method name is overloaded, not hidden.
A call to a static or final method is bound to a method implementation at compile
time (private methods are implicitly final). Example 7.2 illustrates invocation of
static methods. Analogous to accessing fields, the static method invoked in (23), (24), and
(25) is determined by the declared type of the reference. In (23), the declared reference
type is TubeLight; therefore, the static method printLightType() at (10) in this
class is invoked. In (24) and (25), the declared reference type is Light, and the hidden
static method printLightType() at (5) in that class is invoked. This is borne out by
the output from the program.
Analogous to hidden fields, a hidden static method can always be invoked by using the
superclass name or by using the keyword super in non-static code in the subclass
declaration (§7.4, p. 276).
Table 7.2 summarizes the consequences when a subclass method has the same signature as
a method in the superclass.

Table 7.2

Same Signature for Subclass and Superclass Method
WOW! eBook
www.wowebook.org

7.4 The Object Reference
The this reference can be used in non-static code to refer to the current object (§3.2, p.
50). The keyword super, in contrast, can be used in non-static code to access fields and
invoke methods from the superclass (Table 4.1, p. 115). The keyword super provides a
reference to the current object as an instance of its superclass. In method invocations with
super, the method from the superclass is invoked regardless of what the actual type of
the current object is or whether the current class overrides the method. This approach is
typically used to invoke methods that are overridden, and to access members that are
hidden in the subclass. Unlike the this keyword, the super keyword cannot be used as
an ordinary reference. For example, it cannot be assigned to other references or cast to
other reference types.
Example 7.3 uses the classes Light and TubeLight from Example 7.2, which are also
shown in Figure 7.2. In Example 7.3, the class NeonLight extends the class
TubeLight. The declaration of the method demonstrate() at (11) in the class
NeonLight makes use of the super keyword to access members higher up in its
inheritance hierarchy. This is the case when the showSign() method is invoked at (12).
This method is defined at (4) in the class Light, rather than in the immediate superclass
TubeLight of the subclass NeonLight. The overridden method energyCost() at
(7) and its overloaded version at (8) in the class TubeLight are invoked, using the
object reference super at (13) and (14), respectively.
The superclass Light has a field named lightType and a method named
energyCost defined at (1) and (2), respectively. One might be tempted to use the
syntax super.super.energyCost(20) in the subclass NeonLight to invoke this
method, but this is not a valid construct. One might also be tempted to cast the this
reference to the class Light and try again, as shown at (15). The output shows that the
method energyCost() at (7) in the class TubeLight was executed, not the one from
the class Light. The reason is that a cast simply changes the type of the reference (in this
case to Light), not the class of the object (which is still NeonLight). Method
invocation is determined by the class of the current object, resulting in the inherited
method energyCost() in the class TubeLight being executed. There is no way to
invoke the method energyCost() in the class Light from the subclass NeonLight,
without declaring a reference of the type Light.
At (16), the keyword super is used to access the field lightType at (6) in the class
TubeLight, but is redundant in this case. At (17), the field lightType from the class
Light is accessed successfully by casting the this reference, because it is the type of
the reference that determines which field is accessed. From non-static code in a subclass,
it is possible to directly access fields in a class higher up in the inheritance hierarchy by
casting the this reference. However, it is futile to cast the this reference to invoke
instance methods in a class higher up in the inheritance hierarchy, as illustrated earlier for
the overridden method energyCost().
Finally, the calls to the static methods at (18) and (19) using the super and this
WOW! eBook
www.wowebook.org

references, respectively, exhibit runtime behavior analogous to accessing fields, as
discussed previously.
Example 7.3

Using the super Keyword

Click here to view code image
// File: Client3.java
//Exceptions
class InvalidHoursException extends Exception {}
class NegativeHoursException extends InvalidHoursException {}
class ZeroHoursException extends InvalidHoursException {}
class Light {
protected String lightType = “Generic Light”;

// (1) Instance field

protected double energyCost(int noOfHours)
// (2) Instance method
throws InvalidHoursException {
System.out.print(“>> Light.energyCost(int): “);
if (noOfHours < 0)
throw new NegativeHoursException();
double cost = 00.20 * noOfHours;
System.out.println(“Energy cost for ” + lightType + “: ” + cost);
return cost;
}
public Light makeInstance() {
// (3) Instance method
System.out.print(“>> Light.makeInstance(): “);
return new Light();
}
public void showSign() {
System.out.print(“>> Light.showSign(): “);
System.out.println(“Let there be light!”);
}

// (4) Instance method

public static void printLightType() {
// (5) Static method
System.out.print(“>> Static Light.printLightType(): “);
System.out.println(“Generic Light”);
}
}
//______________________________________________________________________________
class TubeLight extends Light {
public static String lightType = “Tube Light”;

// (6) Hiding field at (1).

@Override
public double energyCost(final int noOfHours)
// (7) Overriding instance
throws ZeroHoursException {
//
method at (2).
System.out.print(“>> TubeLight.energyCost(int): “);
if (noOfHours == 0)
throw new ZeroHoursException();
double cost = 00.10 * noOfHours;
System.out.println(“Energy cost for ” + lightType + “: ” + cost);
return cost;
}
public double energyCost() {
// (8) Overloading method at (7).
System.out.print(“>> TubeLight.energyCost(): “);
double flatrate = 20.00;
System.out.println(“Energy cost for ” + lightType + “: ” + flatrate);
WOW! eBook
www.wowebook.org

return flatrate;
}
@Override
public TubeLight makeInstance() {
// (9) Overriding instance method at
(3).
System.out.print(“>> TubeLight.makeInstance(): “);
return new TubeLight();
}
public static void printLightType() { // (10) Hiding static method at (5).
System.out.print(“>> Static TubeLight.printLightType(): “);
System.out.println(lightType);
}
}
//______________________________________________________________________________
class NeonLight extends TubeLight {
// …
public void demonstrate()
// (11)
throws InvalidHoursException {
super.showSign();
// (12) Invokes method at
(4)
super.energyCost(50);
// (13) Invokes method at
(7)
super.energyCost();
// (14) Invokes method at
(8)
((Light) this).energyCost(50);

// (15) Invokes method at

System.out.println(super.lightType);

// (16) Accesses field at

(7)

(6)
System.out.println(((Light) this).lightType); // (17) Accesses field at
(1)
super.printLightType();

// (18) Invokes method at

(10)
((Light) this).printLightType();
// (19) Invokes method at
(5)
}
}
//______________________________________________________________________________
public class Client3 {
public static void main(String[] args)
throws InvalidHoursException {
NeonLight neonRef = new NeonLight();
neonRef.demonstrate();
}
}

Output from the program:
Click here to view code image
>> Light.showSign(): Let there be light!
>> TubeLight.energyCost(int): Energy cost for Tube Light: 5.0
>> TubeLight.energyCost(): Energy cost for Tube Light: 20.0
>> TubeLight.energyCost(int): Energy cost for Tube Light: 5.0
Tube Light
Generic Light
>> Static TubeLight.printLightType(): Tube Light
>> Static Light.printLightType(): Generic Light

WOW! eBook
www.wowebook.org

Review Questions
7.1 Which of the following statements are true?
Select the two correct answers.
(a) In Java, the extends clause is used to specify the inheritance relationship.
(b) The subclass of a non-abstract class can be declared as abstract.
(c) All members of the superclass are inherited by the subclass.
(d) A final class can be abstract.
(e) A class in which all the members are declared private cannot be declared as
public.
7.2 Which of the following statements are true?
Select the two correct answers.
(a) A class can be extended by only one class.
(b) Every Java object has a public method named equals.
(c) Every Java object has a public method named length.
(d) A class can extend any number of classes.
(e) A non-final class can be extended by any number of classes.
7.3 Given the following classes and declarations, which statements are true?
Click here to view code image
// Classes
class Foo {
private int i;
public void f() { /* … */ }
public void g() { /* … */ }
}
class Bar extends Foo {
public int j;
public void g() { /* … */ }
}
// Declarations:
Foo a = new Bar();
Bar b = new Bar();

Select the three correct answers.
(a) The Bar class is a subclass of Foo.
(b) The statement b.f(); is legal.
(c) The statement a.j = 5; is legal.
(d) The statement a.g(); is legal.
WOW! eBook
www.wowebook.org

(e) The statement b.i = 3; is legal.
7.4 Given classes A, B, and C, where B extends A, and C extends B, and where all
classes implement the instance method void doIt(), how can the doIt()
method in A be called from an instance method in C?
Select the one correct answer.
(a) doIt();
(b) super.doIt();
(c) super.super.doIt();
(d) this.super.doIt();
(e) A.this.doIt();
(f) ((A) this).doIt();
(g) It is not possible.
7.5 What would be the result of compiling and running the following program?
Click here to view code image
public class UserClass {
public static void main(String[] args) {
B b = new C();
System.out.println(b.max(13, 29));
}
}
class A {
int max(int x, int y) { if (x>y) return x; else return y; }
}
class B extends A {
int max(int x, int y) { return super.max(y, x) - 10; }
}
class C extends B {
int max(int x, int y) { return super.max(x+10, y+10); }
}

Select the one correct answer.
(a) The code will fail to compile.
(b) The code will compile, but throw an exception at runtime.
(c) The code will compile, and print 13 at runtime.
(d) The code will compile, and print 23 at runtime.
(e) The code will compile, and print 29 at runtime.
(f) The code will compile, and print 39 at runtime.
7.6 Which is the simplest expression that can be inserted at (1), so that the program
prints the value of the text field from the Message class?
WOW! eBook
www.wowebook.org

Click here to view code image
// File: MyClass.java
class Message {
// The message that should be printed:
String text = “Hello, world!”;
}
class MySuperclass {
Message msg = new Message();
}
public class MyClass extends MySuperclass {
public static void main(String[] args) {
MyClass object = new MyClass();
object.print();
}
public void print() {
System.out.println( /* (1) INSERT THE SIMPLEST EXPRESSION HERE */ );
}
}

Select the one correct answer.
(a) text
(b) Message.text
(c) msg.text
(d) this.msg.text
(e) super.msg.text
(f) this.super.msg.text
7.7 What would be the result of compiling and running the following program?
Click here to view code image
class Vehicle {
static public String getModelName() { return “Volvo”; }
public long getRegNo() { return 12345; }
}
class Car extends Vehicle {
static public String getModelName() { return “Toyota”; }
public long getRegNo() { return 54321; }
}
public class TakeARide {
public static void main(String[] args) {
Car c = new Car();
Vehicle v = c;
System.out.println(“|” + v.getModelName() + “|” + c.getModelName() +
”|” + v.getRegNo()
+ “|” + c.getRegNo() +
“|”);
}
}

Select the one correct answer.
WOW! eBook
www.wowebook.org

(a) The code will fail to compile.
(b) The code will compile, and print |Toyota|Volvo|12345|54321| at
runtime.
(c) The code will compile, and print |Volvo|Toyota|12345|54321| at
runtime.
(d) The code will compile, and print |Toyota|Toyota|12345|12345| at
runtime.
(e) The code will compile, and print |Volvo|Volvo|12345|54321| at
runtime.
(f) The code will compile, and print |Toyota|Toyota|12345|12345| at
runtime.
(g) The code will compile, and print |Volvo|Toyota|54321|54321| at
runtime.

7.5 Chaining Constructors Using

and

Constructors are discussed in §3.3, p. 53. Other uses of the keywords this and super
can be found in §7.2, p. 268.

The

Constructor Call

Constructors cannot be inherited or overridden. They can be overloaded, but only in the
same class. Since a constructor always has the same name as the class, each parameter list
must be different when defining more than one constructor for a class. In Example 7.4, the
class Light has three overloaded constructors. In the constructor at (3), the this
reference is used to access the fields shadowed by the parameters. In the main() method
at (4), the appropriate constructor is invoked depending on the arguments in the
constructor call, as illustrated by the program output.

WOW! eBook
www.wowebook.org

Example 7.4

Constructor Overloading

Click here to view code image
// File: DemoConstructorCall.java
class Light {
// Fields:
private int
noOfWatts;
// wattage
private boolean indicator;
// on or off
private String location;
// placement
// Constructors:
Light() {
// (1) No-argument constructor
noOfWatts = 0;
indicator = false;
location = “X”;
System.out.println(“Returning from no-argument constructor no. 1.”);
}
Light(int watts, boolean onOffState) {
// (2)
noOfWatts = watts;
indicator = onOffState;
location = “X”;
System.out.println(“Returning from constructor no. 2.”);
}
Light(int noOfWatts, boolean indicator, String location) { // (3)
this.noOfWatts = noOfWatts;
this.indicator = indicator;
this.location = location;
System.out.println(“Returning from constructor no. 3.”);
}
}
//______________________________________________________________________________
public class DemoConstructorCall {
public static void main(String[] args) {
// (4)
System.out.println(“Creating Light object no. 1.”);
Light light1 = new Light();
System.out.println(“Creating Light object no. 2.”);
Light light2 = new Light(250, true);
System.out.println(“Creating Light object no. 3.”);
Light light3 = new Light(250, true, “attic”);
}
}

Output from the program:
Click here to view code image
Creating Light
Returning from
Creating Light
Returning from
Creating Light
Returning from

object no. 1.
no-argument constructor no. 1.
object no. 2.
constructor no. 2.
object no. 3.
constructor no. 3.

Example 7.5 illustrates the use of the this() construct, which is used to implement local
chaining of constructors in the class when an instance of the class is created. The first two
constructors at (1) and (2) from Example 7.4 have been rewritten using the this()
construct in Example 7.5 at (1) and (2), respectively. The this() construct can be
regarded as being locally overloaded, since its parameters (and hence its signature) can
vary, as shown in the body of the constructors at (1) and (2). The this() call invokes the
WOW! eBook
www.wowebook.org

local constructor with the corresponding parameter list. In the main() method at (4), the
appropriate constructor is invoked depending on the arguments in the constructor call
when each of the three Light objects are created. Calling the no-argument constructor at
(1) to create a Light object results in the constructors at (2) and (3) being executed as
well. This is confirmed by the output from the program. In this case, the output shows that
the constructor at (3) completed first, followed by the constructor at (2), and finally by the
no-argument constructor at (1) that was called first. Bearing in mind the definition of the
constructors, the constructors are invoked in the reverse order; that is, invocation of the
no-argument constructor immediately leads to invocation of the constructor at (2) by the
call this(0, false), and its invocation leads to the constructor at (3) being called
immediately by the call this(watt, ind, "X"), with the completion of the
execution in the reverse order of their invocation. Similarly, calling the constructor at (2)
to create an instance of the Light class results in the constructor at (3) being executed as
well.
Java requires that any this() call must occur as the first statement in a constructor. The
this() call can be followed by any other relevant code. This restriction is due to Java’s
handling of constructor invocation in the superclass when an object of the subclass is
created. This mechanism is explained in the next subsection.

WOW! eBook
www.wowebook.org

Example 7.5

The this() Constructor Call

Click here to view code image
// File: DemoThisCall.java
class Light {
// Fields:
private int
noOfWatts;
private boolean indicator;
private String location;
// Constructors:
Light() {
// (1) No-argument constructor
this(0, false);
System.out.println(“Returning from no-argument constructor no. 1.”);
}
Light(int watt, boolean ind) {
// (2)
this(watt, ind, “X”);
System.out.println(“Returning from constructor no. 2.”);
}
Light(int noOfWatts, boolean indicator, String location) { // (3)
this.noOfWatts = noOfWatts;
this.indicator = indicator;
this.location = location;
System.out.println(“Returning from constructor no. 3.”);
}
}
//______________________________________________________________________________
public class DemoThisCall {
public static void main(String[] args) {
// (4)
System.out.println(“Creating Light object no. 1.”);
Light light1 = new Light();
// (5)
System.out.println(“Creating Light object no. 2.”);
Light light2 = new Light(250, true);
// (6)
System.out.println(“Creating Light object no. 3.”);
Light light3 = new Light(250, true, “attic”);
// (7)
}
}

Output from the program:
Click here to view code image
Creating Light
Returning from
Returning from
Returning from
Creating Light
Returning from
Returning from
Creating Light
Returning from

object no. 1.
constructor no. 3.
constructor no. 2.
no-argument constructor no. 1.
object no. 2.
constructor no. 3.
constructor no. 2.
object no. 3.
constructor no. 3.

WOW! eBook
www.wowebook.org

The

Constructor Call

The super() construct is used in a subclass constructor to invoke a constructor in the
immediate superclass. This allows the subclass to influence the initialization of its
inherited state when an object of the subclass is created. A super() call in the
constructor of a subclass will result in the execution of the relevant constructor from the
superclass, based on the signature of the call. Since the superclass name is known in the
subclass declaration, the compiler can determine the superclass constructor invoked from
the signature of the parameter list.
A constructor in a subclass can access the class’s inherited members by their simple
names. The keyword super can also be used in a subclass constructor to access inherited
members via its superclass. One might be tempted to use the super keyword in a
constructor to specify initial values for inherited fields. However, the super() construct
provides a better solution to initialize the inherited state.
In Example 7.6, the constructor at (3) of the class Light has a super() call (with no
arguments) at (4). Although the constructor is not strictly necessary, as the compiler will
insert one—as explained later—it is included here for expositional purposes. The
constructor at (6) of the class TubeLight has a super() call (with three arguments) at
(7). This super() call will match the constructor at (3) of the superclass Light. This is
evident from the program output.
Example 7.6

The super() Constructor Call

Click here to view code image
// File: Chaining.java
class Light {
// Fields:
private int
noOfWatts;
private boolean indicator;
private String location;
// Constructors:
Light() {
// (1) No-argument constructor
this(0, false);
System.out.println(
“Returning from no-argument constructor no. 1 in class Light”);
}
Light(int watt, boolean ind) {
// (2)
this(watt, ind, “X”);
System.out.println(
“Returning from constructor no. 2 in class Light”);
}
Light(int noOfWatts, boolean indicator, String location) { // (3)
super();
// (4)
this.noOfWatts = noOfWatts;
this.indicator = indicator;
this.location = location;
System.out.println(
“Returning from constructor no. 3 in class Light”);
}
}
//______________________________________________________________________________
class TubeLight extends Light {
WOW! eBook
www.wowebook.org

// Instance variables:
private int tubeLength;
private int colorNo;
// Constructors:
TubeLight(int tubeLength, int colorNo) {
// (5)
this(tubeLength, colorNo, 100, true, “Unknown”);
System.out.println(
“Returning from constructor no. 1 in class TubeLight”);
}
TubeLight(int tubeLength, int colorNo, int noOfWatts,
boolean indicator, String location) {
// (6)
super(noOfWatts, indicator, location);
// (7)
this.tubeLength = tubeLength;
this.colorNo
= colorNo;
System.out.println(
“Returning from constructor no. 2 in class TubeLight”);
}
}
//______________________________________________________________________________
public class Chaining {
public static void main(String[] args) {
System.out.println(“Creating a TubeLight object.”);
TubeLight tubeLightRef = new TubeLight(20, 5);
// (8)
}
}

Output from the program:
Click here to view code image
Creating a TubeLight object.
Returning from constructor no. 3 in class Light
Returning from constructor no. 2 in class TubeLight
Returning from constructor no. 1 in class TubeLight

The super() construct has the same restrictions as the this() construct: If used, the
super() call must occur as the first statement in a constructor, and it can only be used in
a constructor declaration. This implies that this() and super() calls cannot both
occur in the same constructor. The this() construct is used to chain constructors in the
same class. The constructor at the end of such a chain can invoke a superclass constructor
using the super() construct. Just as the this() construct leads to chaining of
constructors in the same class, so the super() construct leads to chaining of subclass
constructors to superclass constructors. This chaining behavior guarantees that all
superclass constructors are called, starting with the constructor of the class being
instantiated, all the way to the top of the inheritance hierarchy, which is always the
Object class. Note that the body of the constructor is executed in the reverse order to the
call order, as the super() call can occur only as the first statement in a constructor. This
order of execution ensures that the constructor from the Object class is completed first,
followed by the constructors in the other classes down to the class being instantiated in the
inheritance hierarchy. It is called (subclass–superclass) constructor chaining. The output
from Example 7.6 clearly illustrates this chain of events when an object of the class
TubeLight is created.
If a constructor at the end of a this() chain (which may not be a chain at all if no
WOW! eBook
www.wowebook.org

this() call is invoked) does not have an explicit call to super(), the call super()
(without the parameters) is implicitly inserted by the compiler to invoke the no-argument
constructor of the superclass. In other words, if a constructor has neither a this() call
nor a super() call as its first statement, the compiler inserts a super() call to the noargument constructor in the superclass. The code
Click here to view code image
class A {
A() {}
// …
}
class B extends A {
// …
}

// No-argument constructor.

// No constructors.

is equivalent to
Click here to view code image
class A {
A() { super(); }
inserted.
// …
}
class B extends A {
B() { super(); }
// …
}

// (1) Call to no-argument superclass constructor

// (2) Default constructor inserted.

where the compiler inserts a super() call in the no-argument constructor for class A at
(1) and inserts the default constructor for class B at (2). The super() call at (2) will
result in a call to the no-argument constructor in B at (1), and the super() call at (1) will
result in a call to the no-argument constructor in the superclass of A—that is, the Object
class.
If a superclass defines just non-zero argument constructors (i.e., only constructors with
parameters), its subclasses cannot rely on the implicit super() call being inserted. This
will be flagged as a compile-time error. The subclasses must then explicitly call a
superclass constructor, using the super() construct with the right arguments.
Click here to view code image
class NeonLight extends TubeLight {
// Field
String sign;
NeonLight() {
super(10, 2, 100, true, “Roof-top”);
sign = “All will be revealed!”;
}
// …

// (1)
// (2) Cannot be commented out.

}

The preceding declaration of the subclass NeonLight provides a no-argument
constructor at (1). The call of the constructor at (2) in the superclass TubeLight cannot
be omitted. If it is omitted, any insertion of a super() call (with no arguments) in this
constructor will try to match a no-argument constructor in the superclass TubeLight,
WOW! eBook
www.wowebook.org

which provides only non-zero argument constructors. The class NeonLight will not
compile unless an explicit valid super() call is inserted at (2).
If the superclass provides just non-zero argument constructors (i.e., it does not have a noargument constructor), this has implications for its subclasses. A subclass that relies on its
default constructor will fail to compile, because the default constructor of the subclass will
attempt to call the (nonexistent) no-argument constructor in the superclass. A constructor
in a subclass must explicitly use the super() call, with the appropriate arguments, to
invoke a non-zero argument constructor in the superclass. This call is necessary because
the constructor in the subclass cannot rely on an implicit super() call to the noargument constructor in the superclass.

Review Questions
7.8 Which constructors can be inserted at (1) in MySub without causing a compiletime error?
Click here to view code image
class MySuper {
int number;
MySuper(int i) { number = i; }
}
class MySub extends MySuper {
int count;
MySub(int count, int num) {
super(num);
this.count = count;
}
// (1) INSERT CONSTRUCTOR HERE
}

Select the one correct answer.
(a) MySub() {}
(b) MySub(int count) { this.count = count; }
(c) MySub(int count) { super(); this.count = count; }
(d) MySub(int count) { this.count = count; super(count);
}
(e) MySub(int count) { this(count, count); }
(f) MySub(int count) { super(count); this(count, 0); }
7.9 Which of the following statements is true?
Select the one correct answer.
(a) A super() or this() call must always be provided explicitly as the first
statement in the body of a constructor.
(b) If both a subclass and its superclass do not have any declared constructors, the
WOW! eBook
www.wowebook.org

implicit default constructor of the subclass will call super() when run.
(c) If neither super() nor this() is specified as the first statement in the body
of a constructor, this() will implicitly be inserted as the first statement.
(d) If super() is the first statement in the body of a constructor, this() can be
declared as the second statement.
(e) Calling super() as the first statement in the body of a constructor of a
subclass will always work, since all superclasses have a default constructor.
7.10 What will the following program print when run?
Click here to view code image
public class MyClass {
public static void main(String[] args) {
B b = new B(“Test”);
}
}
class A {
A() { this(“1”, “2”); }
A(String s, String t) { this(s + t); }
A(String s) { System.out.println(s); }
}
class B extends A {
B(String s) { System.out.println(s); }
B(String s, String t) { this(t + s + “3”); }
B() { super(“4”); };
}

Select the one correct answer.
(a) It will just print Test.
(b) It will print Test followed by Test.
(c) It will print 123 followed by Test.
(d) It will print 12 followed by Test.
(e) It will print 4 followed by Test.

7.6 Interfaces
Extending classes using single implementation inheritance creates new class types. A
superclass reference can refer to objects of its own type and its subclasses strictly
according to the inheritance hierarchy. Because this relationship is linear, it rules out
multiple implementation inheritance, in which a subclass inherits from more than one
superclass. Instead Java provides interfaces, which not only allow new named reference
types to be introduced, but also permit multiple interface inheritance.

WOW! eBook
www.wowebook.org

Defining Interfaces
A top-level interface has the following simplified syntax, which will suffice for the
purposes of this book:
Click here to view code image

accessibility_modifier interface interface_name
extends_interface_clause // Interface
header
{ // Interface body
abstract_method_declarations
default_method_declarations
static_method_declarations
constant_declarations
}
In the interface header, the name of the interface is preceded by the keyword
interface. The interface name can also include a list of formal type parameters for
declaring a generic interface. In addition, the interface header can specify the following
information:
• The accessibility modifier must be public, and the lack of an accessibility
modifier implies package accessibility, as one would expect (§4.5, p. 118).
• The extends interface clause specifies a comma-separated list of any superinterfaces
that the interface extends (p. 294).
The interface body can contain member declarations that include any of the following:
• Abstract method declarations (p. 291)
• Default method declarations (p. 297)
• Static method declarations (p. 300)
• Constant declarations (p. 302)
An interface is abstract by definition, which means that it cannot be instantiated.
Declaring an interface as abstract is superfluous and seldom done in practice. It is the
only non-accessibility modifier that can be specified for a top-level interface (apart from
the keyword strictfp).
The member declarations can appear in any order in the interface body, which can be
empty. Since interfaces are meant to be implemented by classes, interface members
implicitly have public accessibility and the public modifier can be omitted. The
following declaration is an example of a bare-bones interface that has an empty body:
interface Playable { }

Interfaces with empty bodies can be used as markers to tag classes as having a certain
property or behavior. Such interfaces are also called ability interfaces. The Java SE
platform API provides several examples of such marker interfaces—namely,
java.lang.Cloneable, java.io.Serializable, and
WOW! eBook
www.wowebook.org

java.util.EventListener.

Abstract Methods in Interfaces
An interface defines a contract by specifying a set of abstract and default method
declarations, but provides implementations only for the default methods—not for the
abstract methods. The abstract methods in an interface are all implicitly abstract and
public by virtue of their definitions. Only the modifiers abstract and public are
allowed, but these are invariably omitted. An abstract method declaration has the
following simple form in a top-level interface:
Click here to view code image

return_type method_name (formal_parameter_list) throws_clause;
An abstract method declaration is essentially a method header terminated by a semicolon
(;). Note that an abstract method is an instance method whose implementation will be
provided by a class that implements the interface in which the abstract method is declared.
The throws clause is discussed in §6.9, p. 251.
The interface Playable shown next declares an abstract method startPlaying().
That it is public and abstract is implicitly implied.
Click here to view code image
interface Playable {
void startPlaying();
}

// Abstract method: no implementation

An interface that has no direct superinterfaces implicitly declares a public abstract method
for each public instance method in the java.lang.Object class.
In contrast to the syntax of abstract methods in top-level interfaces, abstract methods in
top-level classes must be explicitly specified with the keyword abstract, and can have
public, protected, and package accessibility (§4.8, p. 136).
Functional interfaces, meaning interfaces with a single abstract method, are discussed
together with lambda expressions in §10.2, p. 442.
The rest of this chapter provides numerous examples of using interfaces.

Implementing Interfaces
A class can implement, wholly or partially, zero or more interfaces. A class specifies the
interfaces it implements as a comma-separated list of unique interface names in an
implements clause in the class header. The interface methods must all have public
accessibility when implemented in the class (or its subclasses). A class can neither narrow
the accessibility of an interface method nor specify new exceptions in the method’s
throws clause, as attempting to do so would amount to altering the interface’s contract,
which is illegal. The criteria for overriding methods also apply when implementing
abstract methods (§7.2, p. 268).
A class can provide implementations of methods declared in an interface. To reap the
benefits of interfaces, however, the class must also specify the interface name in its
WOW! eBook
www.wowebook.org

implements clause.
In Example 7.7, the class StackImpl implements the interface IStack. It both
specifies the interface name using the implements clause in its class header at (2) and
provides the implementation for the abstract methods in the interface at (3) and (4).
Changing the public accessibility of these methods in the class will result in a compiletime error, as this would narrow their accessibility.
Example 7.7

Implementing Interfaces

Click here to view code image
// File: RetailSeller.java
interface IStack {
// (1)
void
push(Object item);
Object pop();
}
//______________________________________________________________________________
class StackImpl implements IStack {
// (2)
protected Object[] stackArray;
protected int
tos; // top of stack
public StackImpl(int capacity) {
stackArray = new Object[capacity];
tos
= -1;
}
@Override
public void push(Object item) { stackArray[++tos] = item; }
@Override
public Object pop() {
Object objRef = stackArray[tos];
stackArray[tos] = null;
tos—;
return objRef;
}

// (3)

// (4)

public Object peek() { return stackArray[tos]; }
}
//______________________________________________________________________________
interface ISafeStack extends IStack {
// (5)
boolean isEmpty();
boolean isFull();
}
//______________________________________________________________________________
class SafeStackImpl extends StackImpl implements ISafeStack {
// (6)
public SafeStackImpl(int capacity) { super(capacity); }
@Override public boolean isEmpty() { return tos < 0; }
//
(7)
@Override public boolean isFull() { return tos >= stackArray.length-1; }//
(8)
}
//______________________________________________________________________________
public class StackUser {
public static void main(String[] args) {
SafeStackImpl safeStackRef = new SafeStackImpl(10);
StackImpl
stackRef
= safeStackRef;
WOW! eBook
www.wowebook.org

// (9)

ISafeStack
IStack
Object

isafeStackRef = safeStackRef;
istackRef
= safeStackRef;
objRef
= safeStackRef;

safeStackRef.push(“Dollars”);
stackRef.push(“Kroner”);
System.out.println(isafeStackRef.pop());
System.out.println(istackRef.pop());
System.out.println(objRef.getClass());

// (10)

}
}

Output from the program:
Kroner
Dollars
class SafeStackImpl

A class can choose to implement only some of the abstract methods of its interfaces (i.e.,
give a partial implementation of its interfaces). The class must then be declared as
abstract (§4.6, p. 120). Note that abstract methods cannot be declared as static,
because they comprise the contract fulfilled by the objects of the class implementing the
interface. Abstract methods are always implemented as instance methods.
The interfaces that a class implements and the classes that it extends (directly or
indirectly) are called supertypes of the class. Conversely, the class is a subtype of its
supertypes. Classes implementing interfaces introduce multiple interface inheritance into
their implementation inheritance hierarchy. Even so, regardless of how many interfaces a
class implements directly or indirectly, it provides just a single implementation of any
abstract method declared in multiple interfaces.
Single implementation of an abstract method is illustrated by the following code, where
the Worker class at (5) provides only one implementation of the doIt() method that is
declared in both interfaces, at (1) and (2). The class Worker fulfills the contract for both
interfaces, as the doIt() method declarations at (1) and (2) have the same method
signature and return type. However, the class Combined at (3) declares that it
implements the two interfaces, but does not provide any implementation of the doIt()
method; consequently, it must be declared as abstract.
Click here to view code image
interface IA { int doIt(); }

// (1)

interface IB { int doIt(); }

// (2)

abstract class Combined implements IA, IB { }

// (3)

public class Worker implements IA, IB {
@Override
public int doIt() { return 0; }
}

// (4)
// (5)

If the doIt() methods in the two interfaces at (1) and (2) had the same signatures but
different return types, the Worker class would not be able to implement both interfaces.
This is illustrated by the next code snippet. The doIt() methods at (1) and (2) have the
same signature, but different return types. The Worker class provides two
WOW! eBook
www.wowebook.org

implementations of the doIt() method at (5) and (6), which results in compile-time
errors, because a class cannot have two methods with the same signature but different
return types. Removing either implementation from the Worker class will be flagged as a
compile-time error, because the Worker class will not be implementing both interfaces.
There is no way the Worker class can implement both interfaces, given the declarations
shown in the code. In addition, the abstract class Combined at (3) will not compile,
because it will be inheriting two methods with conflicting abstract method declarations. In
fact, the compiler complains of duplicate methods.
Click here to view code image
interface IA { int doIt(); }

// (1)

interface IB { double doIt(); }

// (2)

abstract class Combined implements IA, IB { }
error.

// (3) Compile-time

public class LameWorker implements IA, IB {
@Override
public int doIt() { return 0; }
error.
@Override
public double doIt() {
error.
System.out.println(“Sorry!”);
return = 0.0;
}
}

// (4)
// (5) Compile-time

// (6) Compile-time

Extending Interfaces
An interface can extend other interfaces, using the extends clause. Unlike when
extending classes, an interface can extend several interfaces. The interfaces extended by
an interface (directly or indirectly) are called superinterfaces. Conversely, the interface is
a subinterface of its superinterfaces. Since interfaces define new reference types,
superinterfaces and subinterfaces are also supertypes and subtypes, respectively.
A subinterface inherits from its superinterfaces, all members of those superinterfaces,
except for the following:
• Abstract or default methods that it overrides (p. 297)
• Any static methods declared in its superinterfaces (p. 300)
• Any constants that it hides (p. 302)
Barring any conflicts, a subinterface inherits abstract and default method declarations that
are not overridden, as well as constants that it does not hide in its superinterfaces.
Abstract, static, and default method declarations can also be overloaded, analogous to
method overloading in classes.
Example 7.7 illustrates the relationships between classes and interfaces. In Example 7.7,
the interface ISafeStack extends the interface IStack at (5). The class
SafeStackImpl both extends the StackImpl class and implements the
WOW! eBook
www.wowebook.org

ISafeStack interface at (6). Both the implementation and the interface inheritance
hierarchies for classes and interfaces defined in Example 7.7 are shown in Figure 7.3.

Figure 7.3

Inheritance Hierarchies

In UML, an interface resembles a class. One way to differentiate between them is to use
an «interface» stereotype, as in Figure 7.3. Interface inheritance is depicted in a similar
manner to implementation inheritance, but is indicated by an unbroken inheritance arrow.
Thinking in terms of types, every reference type in Java is a subtype of the Object class.
In turn, any interface type is also a subtype of the Object class, but it does not inherit
from the Object class. An interface that has no direct superinterfaces implicitly declares
a public abstract method for each public instance method in the Object class.
These abstract method declarations are inherited by all subinterfaces of such an interface.
Note that this does not mean the implementation is inherited. The implicit public
abstract method declarations in an interface allow public instance methods in the
Object class to be invoked on objects referred to by an interface reference. All classes
implement these methods, whether they are inherited or overridden from the Object
class. Any interface can also provide explicit public abstract method declarations
for non-final public instance methods in the Object class.
Click here to view code image
interface IStack {
void
push(Object item);

// (1)

WOW! eBook
www.wowebook.org

Object pop();
@Override boolean equals(Object other);
// public method in Object
class.
@Override String toString();
// public method in Object
class.
//@Override Class getClass(); // Compile-time error! final method in Object
class.
}

It is instructive to consider how the class SafeStackImpl implements the IStack
interface: It inherits the implementations of the push() and pop() methods from its
superclass StackImpl, which itself implements the IStack interface in which these
two methods are declared. The class SafeStackImpl also implements the IStack
interface via the ISafeStack interface. The class SafeStackImpl provides its own
implementation of the isFull() and isEmpty() methods declared in the
ISafeStack interface, and has inherited implementations of the push() and pop()
methods whose declarations the ISafeStack interface inherits from its superinterface
IStack. This is readily evident from the diamond shape of the inheritance hierarchy in
Figure 7.3. Note that there is only one single implementation inheritance into the class
SafeStackImpl—from its superclass StackImpl. Java does not support multiple
implementation inheritance.
The association between a class and any interface it implements is called a realization in
UML. In Figure 7.3, there are three realizations: The class SafeStackImpl implements
the ISafeStack interface and also implicitly implements the IStack interface, and the
class StackImpl implements the IStack interface.
Thus, three different inheritance relations are at work when defining inheritance among
classes and interfaces:
1. Single implementation inheritance hierarchy between classes: a class extends
another class (subclasses–superclasses).
2. Multiple inheritance hierarchy between interfaces: an interface extends other
interfaces (subinterfaces–superinterfaces).
3. Multiple interface inheritance hierarchy between classes and interfaces: a class
implements interfaces (realization).

Interface References
Although interfaces cannot be instantiated, references of an interface type can be declared.
The reference value of an object can be assigned to references of the object’s supertypes.
In Example 7.7, an object of the class SafeStackImpl is created in the main()
method of the class StackUser at (9). The reference value of the object is assigned to
references of all the object’s supertypes, which are used to manipulate the object. The
references are aliases to the same SafeStackImpl object, but they can only be used to
manipulate this object as an object of the reference type. For example, calling the method
isFull() on this object using the stackRef reference will be flagged as a compiletime error, as the class StackImpl does not provide such a method. Polymorphic
behavior of supertype references is discussed in §7.12, p. 329.
WOW! eBook
www.wowebook.org

Default Methods in Interfaces
Only interfaces can define default methods. A default method is an instance method
declared with the keyword default and whose implementation is provided by the
interface. However, a default method in a top-level interface always has public
accessibility, whether the keyword public is specified or not.
Click here to view code image

default return_type method_name (formal_parameter_list) throws_clause
{ implementaion_of_method_body }
A class implementing an interface can optionally decide to override any default method in
the interface. If the class does not override a default method to provide a new
implementation, the default implementation provided by the interface is inherited by the
class.
No other non-accessibility modifiers, such as abstract, final, or static, are
allowed in a default method declaration, except the keyword strictfp. A default
method is not abstract because it provides an implementation; is not final because it
can be overridden; and is not static because it can be invoked only on instances of a
class that implements the interface in which the default method is declared.
Example 7.8 illustrates the use of default methods. The default method
printSlogan() at (1) in the interface ISlogan is overridden at (2) in the class
JavaGuru, and inherited by the class JavaGeek at (3). The output from the program
shows that this is the case.

WOW! eBook
www.wowebook.org

Example 7.8

Default Methods in Interfaces

Click here to view code image
// File: JavaParty.java
interface ISlogan {
default void printSlogan() {
// (1)
System.out.println(“Happiness is getting certified!”);
}
}
//_______________________________________________________________________________
class JavaGuru implements ISlogan {
@Override
public void printSlogan() {
// (2) overrides (1)
System.out.println(“Happiness is catching all the exceptions!”);
}
}
//_______________________________________________________________________________
class JavaGeek implements ISlogan { }
// (3) inherits (1)
//_______________________________________________________________________________
public class JavaParty {
public static void main(String[] args) {
JavaGuru guru = new JavaGuru();
guru.printSlogan();
// (4)
JavaGeek geek = new JavaGeek();
geek.printSlogan();
// (5)
}
}

Output from the program:
Click here to view code image
Happiness is catching all the exceptions!
Happiness is getting certified!

The keyword default in the context of a default method should not be confused with
default or package accessibility of a method in a class, which is implied in the absence of
any accessibility modifier. The keyword default is also used only for default method
declarations in interfaces that provide an implementation for such methods, and not by
classes that override them.
Overriding a default method from an interface does not necessarily imply that a new
implementation is being provided. The default method can also be overridden by
providing an abstract method declaration, as illustrated by the next code snippet. The
default method printSlogan() at (1) in the interface ISlogan is overridden by an
abstract method declaration at (2) and (3) in the interface INewSlogan and the abstract
class JavaMaster, respectively. This strategy effectively forces the subtypes of the
interface INewSlogan and of the abstract class JavaMaster to provide a new
concrete implementation for the method, as one would expect for an abstract method.
Click here to view code image
interface ISlogan {
default void printSlogan() {
// (1) Default method.
System.out.println(“Happiness is getting certified!”);
}
}
WOW! eBook
www.wowebook.org

interface INewSlogan extends ISlogan {
@Override
abstract void printSlogan();
// (2) overrides (1) with abstract
method.
}
abstract class JavaMaster implements ISlogan {
@Override
public abstract void printSlogan(); // (3) overrides (1) with abstract
method.
}

Problems with multiple inheritance can arise when default methods are inherited from
multiple interfaces. Example 7.9 illustrates one such case. The default method
printSlogan() is declared at (1) and (2) in the interfaces ICheapSlogan and
IFunny-Slogan, respectively. The two method declarations have the same signature.
The interface IAvailableSlogan at (3) tries to extend the two interfaces
ICheapSlogan and IFunnySlogan. If this was allowed, the interface
IAvailableSlogan would inherit two implementations of methods that have the same
signature, which of course is not allowed—so the compiler flags it as an error. By the
same token, the compiler flags an error at (4), indicating that the abstract class
Wholesaler cannot inherit two methods with the same signature.
The way out of this dilemma is to override the conflicting methods. The abstract class
RetailSeller that implements the interfaces ICheapSlogan and IFunnySlogan
overrides the conflicting methods by providing an abstract method declaration of the
default method printSlogan() at (5). Similarly, the class NetSeller that
implements the interfaces ICheapSlogan and IFunnySlogan overrides the
conflicting methods by providing an implementation of the default method
printSlogan() at (6).
The upshot of this solution is that clients of the classes RetailSeller and
NetSeller now have to deal with the new declarations of the printSlogan()
method provided by these classes. One such client is the class MutlipleInheritance
at (10), which calls the method printSlogan() on an instance of class NetSeller at
(11). Not surprisingly, the program output shows that the method in the NetSeller class
was executed.
What if the class NetSeller wanted to invoke the default method printSlogan() in
the interfaces it implements? The overridden default method can be called by the
overriding subtype (in this case, NetSeller) using the keyword super in conjunction
with the fully qualified name of the interface and the name of the method, as shown at (8)
and (9). This syntax works for calling overridden default methods in the direct
superinterface, but not at any higher level in the inheritance hierarchy. The class
NetSeller can call only default methods in its direct superinterfaces ICheapSlogan
and IFunnySlogan. It would not be possible for the class NetSeller to call any
default methods inherited by these superinterfaces, even if they had any.

WOW! eBook
www.wowebook.org

Example 7.9

Default Methods and Multiple Inheritance

Click here to view code image
// File: MultipleInheritance.java
interface ICheapSlogan {
default void printSlogan() {
// (1)
System.out.println(“Override, don’t overload.”);
}
}
//_______________________________________________________________________________
interface IFunnySlogan {
default void printSlogan() {
// (2)
System.out.println(“Catch exceptions, not bugs.”);
}
}
//_______________________________________________________________________________
interface IAvailableSlogan
// (3) Compile-time error.
extends ICheapSlogan, IFunnySlogan { }
//_______________________________________________________________________________
abstract class Wholesaler
// (4) Compile-time error.
implements ICheapSlogan, IFunnySlogan { }
//_______________________________________________________________________________
abstract class RetailSeller implements ICheapSlogan, IFunnySlogan {
@Override
// Abstract method.
public abstract void printSlogan();
// (5) overrides (1) and (2).
}
//_______________________________________________________________________________
class NetSeller implements ICheapSlogan, IFunnySlogan {
@Override
// Concrete method.
public void printSlogan() {
// (6) overrides (1) and (2).
System.out.println(“Think outside of the class.”);
}
public void invokeDirect() {
// (7)
ICheapSlogan.super.printSlogan();
// (8) calls
ICheapSlogan.printSlogan()
IFunnySlogan.super.printSlogan();
// (9) calls
IFunnySlogan.printSlogan()
}
}
//_______________________________________________________________________________
public class MultipleInheritance {
// (10)
public static void main(String[] args) {
NetSeller seller = new NetSeller();
seller.printSlogan();
// (11)
seller.invokeDirect();
}
}

Output from the program:
Think outside of the class.
Override, don’t overload.
Catch exceptions, not bugs.

WOW! eBook
www.wowebook.org

Static Methods in Interfaces
An interface can also declare static methods. Static method declarations in a top-level
interface are analogous to static method declarations in a class (§4.8, p. 132). However, a
static method in a top-level interface always has public accessibility, whether the
keyword public is specified or not. As with static methods in a class, the keyword
static is mandatory; otherwise, the code will not compile. Without the keyword
static, the method declaration is identical to that of an instance method, but such
instance methods cannot be declared in an interface.
Click here to view code image

static return_type method_name (formal_parameter_list) throws_clause
{ implementaion_of_method_body }
Static methods in an interface differ from those in a class in one important respect: Static
methods in an interface cannot be inherited, unlike static methods in classes. This
essentially means that such methods cannot be invoked directly by calling the method in
subinterfaces or in classes that extend or implement interfaces containing such methods,
respectively. A static method can be invoked only by using its qualified name—that is, the
name of the interface in which it is declared—together with its simple name, using the dot
notation (.).
Example 7.10 illustrates the use of static methods in interfaces. The static method
getNumOfCylinders() at (1) is declared in the IMaxEngineSize interface. There
are two implementations of the method getEngineSize(), at (2) and (3), in the
interface IMaxEngineSize and its subinterface INewEngineSize, respectively. The
class CarRace implements the subinterface INewEngineSize.
It is not possible to invoke the method getNumOfCylinders() directly, as shown at
(4). It is also not possible to invoke directly the method getEngineSize() from either
interface, as shown at (6). The respective implementations of the static methods can be
invoked only by using their qualified names, as shown at (5), (7) and (8). It does not
matter that a static method is redeclared in a subinterface; the static method is not
inherited. Each static method declaration in Example 7.10 is a new method.

WOW! eBook
www.wowebook.org

Example 7.10

Static Methods in Interfaces

Click here to view code image
// File: CarRace.java
import static java.lang.System.out;
interface IMaxEngineSize {
static int getNumOfCylinders() { return 6; }
// (1) Static method
static double getEngineSize() { return 1.6; }
// (2) Static method
}
//_______________________________________________________________________________
interface INewEngineSize extends IMaxEngineSize {
static double getEngineSize() { return 2.4; }
// (3) Static method
}
//_______________________________________________________________________________
public class CarRace implements INewEngineSize {
public static void main(String[] args) {
// out.println(“No. of cylinders: ” +
//
getNumOfCylinders());
// (4) Compile-time
error.
out.println(“No. of cylinders: ” +
IMaxEngineSize.getNumOfCylinders());
// (5)
// out.println(“Engine size: ” + getEngineSize());
// (6) Compile-time
error.
out.println(“Max engine size: ” + IMaxEngineSize.getEngineSize()); // (7)
out.println(“New engine size: ” + INewEngineSize.getEngineSize()); // (8)
}
}

Output from the program:
No. of cylinders: 6
Max engine size: 1.6
New engine size: 2.4

Constants in Interfaces
An interface can also define named constants. Naming conventions recommend using
uppercase letters for their names, with multiple words in the name being separated by
underscores. Such constants are defined by field declarations and are considered to be
public, static, and final. These modifiers can be omitted from the declaration.
Such a constant must be initialized with an initializer expression.
An interface constant can be accessed by any client (a class or interface) using its qualified
name, regardless of whether the client extends or implements its interface. However, if the
client is a class that implements this interface or is an interface that extends this interface,
then the client can also access such constants directly by their simple names. Such a client
inherits the interface constants. Typical usage of constants in interfaces is illustrated in
Example 7.11, showing access both by the constant’s simple name and its qualified name
in the print statements at (1) and (2), respectively.

WOW! eBook
www.wowebook.org

Example 7.11

Constants in Interfaces

Click here to view code image
// File: Client.java
interface Constants {
double PI_APPROXIMATION = 3.14;
String AREA_UNITS
= “sq.cm.”;
String LENGTH_UNITS
= “cm.”;
}
//______________________________________________________________________________
public class Client implements Constants {
public static void main(String[] args) {
double radius = 1.5;
// (1) Using simple name:
System.out.printf(“Area of circle is %.2f %s%n”,
PI_APPROXIMATION * radius*radius, AREA_UNITS);
// (2) Using qualified name:
System.out.printf(“Circumference of circle is %.2f %s%n”,
2.0 * Constants.PI_APPROXIMATION * radius,
Constants.LENGTH_UNITS);
}
}

Output from the program:
Click here to view code image
Area of circle is 7.06 sq.cm.
Circumference of circle is 9.42 cm.

Extending an interface that has constants is analogous to extending a class having static
variables. This is illustrated by Figure 7.4 and Example 7.12. Note the diamond shape of
the inheritance hierarchy, indicating the presence of multiple inheritance paths through
which constants can be inherited. The constants IDLE and BUSY at (1) and (2) in the
interface IBaseStates are inherited by the subinterface IAllStates via both the
interface IExtStatesA and the interface IExtStatesB. In such cases, the constant is
considered to be inherited only once, and can be accessed by its simple name, as shown at
(12) in Example 7.12.

WOW! eBook
www.wowebook.org

Figure 7.4

Inheritance Relationships for Interface Constants

Constants can be hidden by the subinterfaces. The declaration of the constant BLOCKED at
(6) in the interface IAllStates hides the declaration of the constant at (2) in the
interface IBaseStates. The new declaration can be accessed by its simple name in a
class implementing the interface IAllStates, as shown at (10) in Example 7.12. The
hidden constant declaration can always be accessed by using its qualified name as shown
at (11) in Example 7.12.
In the case of multiple inheritance of interface constants, any name conflicts can be
resolved by using the qualified name to access the constants. This is illustrated by the
constant DISMANTLED, which is declared in both the IExtStatesA and
IExtStatesB interfaces. Both declarations are inherited by the subinterface
IAllStates. Such declarations are said to be ambiguous. The compiler will report an
error only if such constants are accessed by their simple names, as shown at (7) and (8) for
the constant DISMANTLE. Only the qualified name can be used to disambiguate such
constants and resolve the conflict, as shown at (7a) and (8a) for the constant
DISMANTLE.
When defining a set of related constants, the recommended practice is to use an
enumerated type, rather than named constants in an interface.

WOW! eBook
www.wowebook.org

Example 7.12

Inheriting Constants in Interfaces

Click here to view code image
// File: Factory.java
interface IBaseStates {
String IDLE = “idle”;
// (1)
String BUSY = “busy”;
// (2)
String BLOCKED = “blocked”;
// (3)
}
//_______________________________________________________________________________
interface IExtStatesA extends IBaseStates {
String DISMANTLED = “dismantled”;
// (4)
}
//_______________________________________________________________________________
interface IExtStatesB extends IBaseStates {
String DISMANTLED = “kaput”;
// (5)
}
//_______________________________________________________________________________
interface IAllStates extends IExtStatesB, IExtStatesA {
String BLOCKED = “out of order”;
// (6) hides (3)
//String ABSOLETE = BLOCKED + “, ” +
//
DISMANTLED + ” and scrapped.”;
// (7) Ambiguous
String ABSOLETE = BLOCKED + “, ” +
IExtStatesB.DISMANTLED + ” and scrapped”;
// (7a)
}
//_______________________________________________________________________________
public class Factory implements IAllStates {
public static void main(String[] args) {
// System.out.println(“Machine A is ” + DISMANTLED);
// (8)
Ambiguous.
System.out.println(“Machine A is ” + IExtStatesB.DISMANTLED);// (8a)
System.out.println(“Machine B is ” + ABSOLETE);
//
(9) IAllStates.ABSOLETE
System.out.println(“Machine C is ” + BLOCKED);
// (10)
IAllStates.BLOCKED
System.out.println(“Machine D is ” + IBaseStates.BLOCKED); // (11)
System.out.println(“Machine E is ” + BUSY);
// (12) Simple name
}
}

Output from the program:
Click here to view code image
Machine
Machine
Machine
Machine
Machine

A
B
C
D
E

is
is
is
is
is

kaput
out of order, kaput and scrapped
out of order
blocked
busy

Review Questions
7.11 Which of the following statements about interfaces are true?
Select the two correct answers.
(a) Interfaces allow multiple implementation inheritance.
(b) Interfaces can be extended by any number of interfaces.
WOW! eBook
www.wowebook.org

(c) Interfaces can extend any number of interfaces.
(d) Members of an interface are never static.
(e) Members of an interface can always be declared static.
7.12 Which modifiers can methods declared in a top-level interface specify?
Select the four correct answers.
(a) public
(b) protected
(c) private
(d) default
(e) abstract
(f) static
(g) final
7.13 Which modifiers are implicitly implied for interface variables?
Select the three correct answers.
(a) public
(b) protected
(c) private
(d) default
(e) abstract
(f) static
(g) final
7.14 How many errors will the compiler report for the following code?
Click here to view code image
public interface Vehicle {
final static int NUMBER_OF_HEADLIGHTS; // (1)
void increaseSpeed(int increment) {
// (2)
System.out.println(“Increasing speed by ” + increment);
}
static void reduceSpeed(int decrement); // (3)
final default void stop() {
// (4)
System.out.println(“Slamming the brakes!”);
}
}

Select the one correct answer.
(a) No errors
(b) 1 error
WOW! eBook
www.wowebook.org

(c) 2 errors
(d) 3 errors
(e) More than 3 errors
7.15 Which method calls can be inserted at both (1) and (2), so that the following code
will still compile?
Click here to view code image

// File: Company.java
interface ISlogan {
String SLOGAN = “Happiness shared is happiness doubled!”;
default void printSlogan() { System.out.println(SLOGAN); }
}
//_____________________________________________________________________________
public class Company implements ISlogan {
public static void main(String[] args) {
Company co = new Company();
ISlogan sl = co;
// (1) INSERT THE METHOD CALL HERE.
}
public void testSlogan() {
Company co = new Company();
ISlogan sl = co;
// (2) INSERT THE METHOD CALL HERE.
}
}

Select the two correct answers.
(a) printSlogan();
(b) co.printSlogan();
(c) sl.printSlogan();
(d) Company.printSlogan();
(e) ISlogan.printSlogan();
7.16 Which method call can be inserted at both (1) and (2), so that the following code
will still compile?
Click here to view code image

// File: Firm.java
interface INewSlogan {
String SLOGAN = “Trouble shared is trouble halved!”;
static void printSlogan() { System.out.println(SLOGAN); }
}
//_____________________________________________________________________________
public class Firm implements INewSlogan {
public static void main(String[] args) {
Firm co = new Firm();
INewSlogan sl = co;
// (1) INSERT THE STATEMENT EXPRESSION HERE.
}
void testSlogan() {
Firm co = new Firm();
WOW! eBook
www.wowebook.org

INewSlogan sl = co;
// (2) INSERT THE STATEMENT EXPRESSION HERE.
}
}

Select the one correct answer.
(a) printSlogan();
(b) co.printSlogan();
(c) sl.printSlogan();
(d) Firm.printSlogan();
(e) INewSlogan.printSlogan();
7.17 What will the following program print when compiled and run?
Click here to view code image
// File: RaceA.java
interface IJogger {
default boolean justDoIt(String msg) { return false; }
static boolean justDoIt(int i)
{ return true; }
}
class Athlete implements IJogger {
public boolean justDoIt(String msg)
public boolean justDoIt(int i)
}

{ return true; }
{ return false; }

public class RaceA {
public static void main(String[] args) {
Athlete athlete = new Athlete();
IJogger jogger = athlete;
System.out.print(jogger.justDoIt(“Run”));
System.out.println(“|” + athlete.justDoIt(10));
}
}

Select the one correct answer.
(a) The program will not compile.
(b) true|true
(c) true|false
(d) false|true
(e) false|false
7.18 What will the following program print when compiled and run?
Click here to view code image
// File: HouseC
interface ISwitch {
default boolean isOn() { return false; }
}
class Light implements ISwitch {
boolean isOn() { return true; }
WOW! eBook
www.wowebook.org

// (1)

// (2)

// (1)
// (2)

// (3)
// (4)

// (5)
// (6)

}
public class HouseC {
public static void main(String[] args) {
ISwitch lightswitch = new Light();
System.out.println(lightswitch.isOn());
}
}

Select the one correct answer.
(a) The program will not compile.
(b) The program will compile, and print true when run.
(c) The program will compile, and print false when run.
(d) The program will compile, and throw an exception when run.
7.19 Which of these field declarations are legal within the body of an interface?
Select the three correct answers.
(a) public static int ANSWER = 42;
(b) int ANSWER;
(c) static final int ANSWER = 42;
(d) public int ANSWER = 42;
(e) private static final int ANSWER = 42;
7.20 Which statements about the keywords extends and implements are true?
Select the two correct answers.
(a) The keyword extends is used to specify that an interface inherits from
another interface.
(b) The keyword extends is used to specify that a class implements an interface.
(c) The keyword implements is used to specify that an interface inherits from
another interface.
(d) The keyword implements is used to specify that a class inherits from an
interface.
(e) The keyword implements is used to specify that a class inherits from another
class.
7.21 Which statement is true about the following code?
Click here to view code image
// File:
abstract
public
public
}

MyClass.java
class MyClass implements Interface1, Interface2 {
void f() { }
void g() { }

interface Interface1 {
WOW! eBook
www.wowebook.org

int VAL_A = 1;
int VAL_B = 2;
void f();
void g();
}
interface Interface2 {
int VAL_B = 3;
int VAL_C = 4;
void g();
void h();
}

Select the one correct answer.
(a) MyClass implements only Interface1; the implementation for void
h() from Interface2 is missing.
(b) The declarations of void g() in the two interfaces are in conflict, so the code
will not compile.
(c) The declarations of int VAL_B in the two interfaces are in conflict, so the
code will not compile.
(d) Nothing is wrong with the code; it will compile without errors.
7.22 Which declaration can be inserted at (1) without resulting in a compile-time error?
interface MyConstants {
int R = 42;
int S = 69;
// (1) INSERT CODE HERE
}

Select the two correct answers.
(a) final double CIRCUMFERENCE = 2 * Math.PI * R;
(b) int TOTAL = TOTAL + R + S;
(c) int AREA = R * S;
(d) public static MAIN = 15;
(e) protected int CODE = 13082009;

7.7 Arrays and Subtyping
Table 7.3 summarizes the types found in Java. Only primitive data and reference values
can be stored in variables. Only class and array types can be explicitly instantiated to
create objects.

WOW! eBook
www.wowebook.org

Table 7.3

Types and Values

Arrays and Subtype Covariance
Arrays are objects in Java. Array types (boolean[], Object[], StackImpl[])
implicitly augment the inheritance hierarchy. The inheritance hierarchy depicted in Figure
7.3, for example, can be augmented by the corresponding array types to produce the type
hierarchy shown in Figure 7.5. An array type is shown as a “class” with the [] notation
appended to the name of the element type. The class SafeStackImpl is a subclass of
the class StackImpl. The corresponding array types, SafeStackImpl[] and
StackImpl[], are shown as the subtype and the supertype, respectively, in the type
hierarchy. Figure 7.5 also shows array types corresponding to some of the primitive data
types.

Figure 7.5

Reference Type Hierarchy: Arrays and Subtype Covariance

From the type hierarchy in Figure 7.5, the following facts are apparent:
• All reference types are subtypes of the Object type. This applies to classes,
interfaces, enums, and array types, as these are all reference types.
• All arrays of reference types are also subtypes of the array type Object[], but
arrays of primitive data types are not. Note that the array type Object[] is also a
subtype of the Object type.
• If a non-generic reference type is a subtype of another non-generic reference type,
WOW! eBook
www.wowebook.org

the corresponding array types also have an analogous subtype–supertype
relationship. This is called the subtype covariance relationship.
• There is no subtype–supertype relationship between a type and its corresponding
array type.
We can create an array of an interface type, but we cannot instantiate an interface (as is the
case with abstract classes). In the following declaration statement, the reference
iSafeStackArray has type ISafeStack[] (i.e., an array of the interface type
ISafeStack):
Click here to view code image
ISafeStack[] iSafeStackArray = new ISafeStack[5];

The array creation expression creates an array whose element type is ISafeStack. The
array object can accommodate five references of the type ISafeStack. The declaration
statement does not initialize these references to refer to any objects; instead, they are
initialized to the default value null.

Array Store Check
An array reference exhibits polymorphic behavior like any other reference, subject to its
location in the type hierarchy (§7.12, p. 329). However, a runtime check is necessary
when objects are inserted in an array, as the next example illustrates.
The following assignment is valid, as a supertype reference (StackImpl[]) can refer to
objects of its subtype (SafeStackImpl[]):
Click here to view code image
StackImpl[] stackImplArray = new SafeStackImpl[2];

// (1)

Since StackImpl is a supertype of SafeStackImpl, the following assignment is also
valid:
Click here to view code image
stackImplArray[0] = new SafeStackImpl(10);

// (2)

The assignment at (2) assigns the reference value of a new SafeStackImpl object to
the reference at index 0 in the SafeStackImpl[] object (i.e., the array of
SafeStackImpl) created at (1).
Since the type of stackImplArray[i], (0 ≤ i < 2), is StackImpl, it should be
possible to make the following assignment as well:
Click here to view code image
stackImplArray[1] = new StackImpl(20);
ArrayStoreException

// (3)

At compile time there are no problems, as the compiler cannot deduce that the array
variable stackImplArray will actually denote a SafeStackImpl[] object at
runtime. However, the assignment at (3) results in an ArrayStoreException being
thrown at runtime, because an array of SafeStackImpl objects cannot possibly contain
objects of its supertype StackImpl.
WOW! eBook
www.wowebook.org

The array store check at runtime ensures that an object being stored in the array is
assignment compatible (p. 314) with the element type of the array. To make the array store
check feasible at runtime, the array retains information about its declared element type at
runtime.

7.8 Reference Values and Conversions
A review of conversions (§5.1, p. 144) is recommended before proceeding with this
section.
Reference values, like primitive values, can be assigned, cast, and passed as arguments.
Conversions can occur in the following contexts:
• Assignment
• Method invocation
• Casting
The rule of thumb for the primitive data types is that widening conversions are permitted,
but narrowing conversions require an explicit cast. The rule of thumb for reference values
is that widening conversions up the type hierarchy are permitted, but narrowing
conversions down the hierarchy require an explicit cast. In other words, conversions that
are from a subtype to its supertypes are allowed, but other conversions require an explicit
cast or are otherwise illegal. There is no notion of promotion for reference values.

7.9 Reference Value Assignment Conversions
In the context of assignments, the following conversions are permitted (Table 5.1, p. 147):
• Widening primitive and reference conversions (long ← int, Object ←
String)
• Boxing conversion of primitive values, followed by optional widening reference
conversion (Integer ← int, Number ← Integer ← int)
• Unboxing conversion of a primitive value wrapper object, followed by optional
widening primitive conversion (long ← int ← Integer)
For assignment conversions only, the following conversions are also possible:
• Narrowing conversion for constant expressions of non-long integer types, with
optional boxing (Byte ← byte ← int)
Note that these rules imply that a widening conversion cannot be followed by any boxing
conversion, but the converse is permitted.
Widening reference conversions typically occur during assignment up the type hierarchy,
with implicit conversion of the source reference value to that of the destination reference
type:
Click here to view code image
Object obj = “Up the tree”;
// Widening reference conversion: Object <—
String
String str1 = obj;
// Not OK. Narrowing reference conversion requires a
WOW! eBook
www.wowebook.org

cast.
String str2 = new Integer(10); // Illegal. No relation between String and
Integer.

The source value can be a primitive value, in which case the value is boxed in a wrapper
object corresponding to the primitive type. If the destination reference type is a supertype
of the wrapper type, a widening reference conversion can occur:
Click here to view code image
Integer iRef = 10;
Number num = 10L;
Object obj = 100;

// Only boxing
// Boxing, followed by widening: Number <– Long <– long
// Boxing, followed by widening: Object <– Integer <– int

More examples of boxing during assignment can be found in §5.1, p. 145.
Example 7.13

Assigning and Passing Reference Values

Click here to view code image
interface IStack
interface ISafeStack extends IStack
class StackImpl implements IStack
class SafeStackImpl extends StackImpl
implements ISafeStack

{ /* From Example 7.7 */ }
{ /* From Example 7.7 */ }
{ /* From Example 7.7 */ }
{ /* From Example 7.7 */ }

public class ReferenceConversion {
public static void main(String[] args) {
// Reference declarations:
Object
objRef;
StackImpl
stackRef;
SafeStackImpl safeStackRef;
IStack
iStackRef;
ISafeStack
iSafeStackRef;
// SourceType
safeStackRef
objRef
stackRef
iStackRef
iSafeStackRef
ISafeStack

is a class type:
= new SafeStackImpl(10);
= safeStackRef;
// (1)
= safeStackRef;
// (2)
= stackRef;
// (3)
= safeStackRef;
// (4)

Always possible
Subclass to superclass assignment
StackImpl implements IStack
SafeStackImpl implements

// SourceType is an interface type:
objRef
= iStackRef;
// (5) Always possible
iStackRef = iSafeStackRef;
// (6) Sub- to super-interface
assignment
// SourceType is an array type:
Object[]
objArray
StackImpl[]
stackArray
SafeStackImpl[] safeStackArray
ISafeStack[]
iSafeStackArray
int[]
intArray
// Reference
objRef
=
objRef
=
objArray
=
objArray
=
objRef
=
// objArray

value assignments:
objArray;
stackArray;
stackArray;
iSafeStackArray;
intArray;
= intArray;

=
=
=
=
=

new
new
new
new
new

//
//
//
//
//
//

Object[3];
StackImpl[3];
SafeStackImpl[5];
ISafeStack[5];
int[10];

(7) Always possible
(8) Always possible
(9) Always possible
(10) Always possible
(11) Always possible
(12) Compile-time error:

WOW! eBook
www.wowebook.org

//
int[] not subtype of Object[]
stackArray = safeStackArray;
// (13) Subclass array to superclass
array
iSafeStackArray = safeStackArray;// (14) SafeStackImpl implements
ISafeStack
// Method invocation conversions:
System.out.println(“First call:”);
sendParams(stackRef, safeStackRef, iStackRef,
safeStackArray, iSafeStackArray);
// (15)
// Call Signature: sendParams(StackImpl, SafeStackImpl, IStack,
//
SafeStackImpl[], ISafeStack[]);
System.out.println(“Second call:”);
sendParams(iSafeStackArray, stackRef, iSafeStackRef,
stackArray, safeStackArray);
// (16)
// Call Signature: sendParams(ISafeStack[], StackImpl, ISafeStack,
//
StackImpl[], SafeStackImpl[]);
}
public static void sendParams(Object objRefParam, StackImpl stackRefParam,
IStack iStackRefParam, StackImpl[] stackArrayParam,
IStack[] iStackArrayParam) {
// (17)
// Signature: sendParams(Object, StackImpl, IStack, StackImpl[],
IStack[])
// Print class name of object denoted by the reference at runtime.
System.out.println(objRefParam.getClass());
System.out.println(stackRefParam.getClass());
System.out.println(iStackRefParam.getClass());
System.out.println(stackArrayParam.getClass());
System.out.println(iStackArrayParam.getClass());
}
}

Output from the program:
First call:
class SafeStackImpl
class SafeStackImpl
class SafeStackImpl
class [LSafeStackImpl;
class [LSafeStackImpl;
Second call:
class [LSafeStackImpl;
class SafeStackImpl
class SafeStackImpl
class [LSafeStackImpl;
class [LSafeStackImpl;

The rules for reference value assignment are stated in this section, based on the following
code:
Click here to view code image
SourceType srcRef;
// srcRef is appropriately initialized.
DestinationType destRef = srcRef;

If an assignment is legal, the reference value of srcRef is said to be assignable (or
assignment compatible) to the reference of DestinationType. The rules are illustrated
by concrete cases from Example 7.13. Note that the code in Example 7.13 uses reference
types from Example 7.7, p. 292.
WOW! eBook
www.wowebook.org

• If the SourceType is a class type, the reference value in srcRef may be assigned
to the destRef reference, provided the DestinationType is one of the
following:
DestinationType is a superclass of the subclass SourceType.
DestinationType is an interface type that is implemented by the class
SourceType.
Click here to view code image
objRef
stackRef
iStackRef
iSafeStackRef
ISafeStack

=
=
=
=

safeStackRef;
safeStackRef;
stackRef;
safeStackRef;

//
//
//
//

(1)
(2)
(3)
(4)

Always possible
Subclass to superclass assignment
StackImpl implements IStack
SafeStackImpl implements

• If the SourceType is an interface type, the reference value in srcRef may be
assigned to the destRef reference, provided the DestinationType is one of
the following:
DestinationType is the Object class.
DestinationType is a superinterface of the subinterface SourceType.
Click here to view code image
objRef
= iStackRef;
// (5) Always possible
iStackRef = iSafeStackRef; // (6) Subinterface to superinterface
assignment

• If the SourceType is an array type, the reference value in srcRef may be
assigned to the destRef reference, provided the DestinationType is one of
the following:
DestinationType is the Object class.
DestinationType is an array type, where the element type of the
SourceType is assignable to the element type of the DestinationType.
Click here to view code image
objRef
=
objRef
=
objArray
=
objArray
=
objRef
=
// objArray

objArray;
stackArray;
stackArray;
iSafeStackArray;
intArray;
= intArray;

//
//
//
//
//
//
//
//

(7) Always possible
(8) Always possible
(9) Always possible
(10) Always possible
(11) Always possible
(12) Compile-time error:
int[] not subtype of Object[]
(13) Subclass array to superclass

stackArray = safeStackArray;
array
iSafeStackArray = safeStackArray;// (14) SafeStackImpl implements
ISafeStack

The rules for assignment are enforced at compile time, guaranteeing that no type
conversion error will occur during assignment at runtime. Such conversions are type-safe.
The reason the rules can be enforced at compile time is that they concern the declared type
of the reference (which is always known at compile time) rather than the actual type of the
object being referenced (which is known at runtime).
WOW! eBook
www.wowebook.org

7.10 Method Invocation Conversions Involving References
The conversions for reference value assignment are also applicable to method invocation
conversions, except for the narrowing conversion for constant expressions of non-long
integer type (Table 5.1, p. 147). This is reasonable, as parameters in Java are passed by
value (§3.5, p. 72), requiring that values of the actual parameters must be assignable to
formal parameters of the compatible types.
In Example 7.13, the method sendParams() at (17) has the following signature,
showing the types of the formal parameters:
Click here to view code image
sendParams(Object, StackImpl, IStack, StackImpl[], IStack[])

The method call at (15) has the following signature, showing the types of the actual
parameters:
Click here to view code image
sendParams(StackImpl, SafeStackImpl, IStack, SafeStackImpl[], ISafeStack[]);

Note that the assignment of the values of the actual parameters to the corresponding
formal parameters is legal, according to the rules for assignment discussed earlier. The
method call at (16) provides another example of the parameter passing conversion. It has
the following signature:
Click here to view code image
sendParams(ISafeStack[], StackImpl, ISafeStack, StackImpl[],
SafeStackImpl[]);

Analogous to assignment, the rules for parameter passing conversions are based on the
reference type of the parameters and are enforced at compile time. The output in Example
7.13 shows the class of the actual objects referenced by the formal parameters at runtime,
which in this case turns out to be either SafeStackImpl or SafeStackImpl[]. The
characters [L in the output indicate a one-dimensional array of a class or interface type
(see the Class.getName() method in the Java SE platform API documentation).

Overloaded Method Resolution
In this subsection, we take a look at some aspects regarding overloaded method resolution
—namely, how the compiler determines which overloaded method will be invoked by a
given method call at runtime.
Resolution of overloaded methods selects the most specific method for execution. One
method is considered more specific than another method if all actual parameters that can
be accepted by the one method can be accepted by the other method. If more than one
such method is present, the call is described as ambiguous. The following overloaded
methods illustrate this situation:
Click here to view code image
private static void
out.println(str
}
private static void
out.println(str

flipFlop(String str, int i, Integer iRef) { // (1)
+ ” ==> (String, int, Integer)”);
flipFlop(String str, int i, int j) {
+ ” ==> (String, int, int)”);
WOW! eBook
www.wowebook.org

// (2)

}

Their method signatures follow:
Click here to view code image
flipFlop(String, int, Integer)
flipFlop(String, int, int)

// See (1)
// See (2)

The following method call is ambiguous:
Click here to view code image
flipFlop(“(String, Integer, int)”, new Integer(4), 2004);
call

// (3) Ambiguous

It has the call signature:
Click here to view code image
flipFlop(String, Integer, int)

// See (3)

The method at (1) can be called with the second argument unboxed and the third argument
boxed, as can the method at (2) with only the second argument unboxed. In other words,
for the call at (3), none of the methods is more specific than the others.
Example 7.14 illustrates a simple case of how method resolution is done to choose the
most specific overloaded method. The method testIfOn() is overloaded at (1) and (2)
in the class Overload. The call client.testIfOn(tubeLight) at (3) satisfies
the parameter lists in both implementations given at (1) and (2), as the reference
tubeLight can also be assigned to a reference of its superclass Light. The most
specific method, (2), is chosen, resulting in false being written on the terminal. The call
client.testIfOn(light) at (4) satisfies only the parameter list in the
implementation given at (1), resulting in true being written on the terminal. This is also
the case at (5). The object referred to by the argument in the call is irrelevant; rather, it is
the type of the argument that is important for overloaded method resolution.

WOW! eBook
www.wowebook.org

Example 7.14

Choosing the Most Specific Method (Simple Case)

Click here to view code image
class Light { /* … */ }
class TubeLight extends Light { /* … */ }
public class Overload {
boolean testIfOn(Light aLight)
{ return true; }
boolean testIfOn(TubeLight aTubeLight) { return false; }

// (1)
// (2)

public static void main(String[] args) {
TubeLight tubeLight = new TubeLight();
Light
light
= new Light();
Light
light2
= new TubeLight();
Overload client = new Overload();
System.out.println(client.testIfOn(tubeLight)); // (3) ==> method at (2)
System.out.println(client.testIfOn(light));
// (4) ==> method at (1)
System.out.println(client.testIfOn(light2));
// (5) ==> method at (2)
}
}

Output from the program:
false
true
true

The algorithm used by the compiler for the resolution of overloaded methods incorporates
the following phases:
1. The compiler performs overload resolution without permitting boxing, unboxing, or
the use of a variable arity call.
2. If phase (1) fails, the compiler performs overload resolution allowing boxing and
unboxing, but excluding the use of a variable arity call.
3. If phase (2) fails, the compiler performs overload resolution combining a variable
arity call, boxing, and unboxing.
Example 7.15 provides some insight into how the compiler determines the most specific
overloaded method using these three phases. The example has six overloaded declarations
of the method action(). The signature of each method is given by the local variable
signature in each method. The first formal parameter of each method is the signature
of the call that invoked the method. The printout from each method allows us to see which
method call resolved to which method. The main() method contains 10 calls, (8) to (17),
of the action() method. In each call, the first argument is the signature of that method
call.
An important point to note is that the compiler chooses a fixed arity call over a variable
arity call, as seen in the calls from (8) to (12):

WOW! eBook
www.wowebook.org

An unboxing conversion (Integer to int) takes place for the call at (10). A widening
primitive conversion (byte to int) takes place for the call at (11).
Variable arity calls are chosen from (13) to (17):

When a variable arity call is chosen, the method determined has the most specific variable
arity parameter that is applicable for the actual argument. For example, in the method call
at (14), the type Integer[] is more specific than either Number[] or Object[].
Note also the boxing of the elements of the implicitly created array in the calls from (13)
to (17).
Example 7.15

Overloaded Method Resolution

Click here to view code image
import static java.lang.System.out;
class OverloadResolution {
public void action(String str) {
String signature = “(String)”;
out.println(str + ” => ” + signature);
}

// (1)

public void action(String str, int m) {
String signature = “(String, int)”;
out.println(str + ” => ” + signature);
}

// (2)

public void action(String str, int m, int n) {
String signature = “(String, int, int)”;
out.println(str + ” => ” + signature);
}

// (3)

public void action(String str, Integer… data) { // (4)
String signature = “(String, Integer[])”;
out.println(str + ” => ” + signature);
}
public void action(String str, Number… data) {
String signature = “(String, Number[])”;
out.println(str + ” => ” + signature);
}

// (5)

public void action(String str, Object… data) {

// (6)

WOW! eBook
www.wowebook.org

String signature = “(String, Object[])”;
out.println(str + ” => ” + signature);
}
public static void main(String[] args) {
OverloadResolution ref = new OverloadResolution();
ref.action(“(String)”);
(1)
ref.action(“(String, int)”,
10);
(2)
ref.action(“(String, Integer)”,
new Integer(10));
(2)
ref.action(“(String, int, byte)”,
10, (byte)20);
(3)
ref.action(“(String, int, int)”,
10, 20);
(3)
ref.action(“(String, int, long)”,
10, 20L);
(5)
ref.action(“(String, int, int, int)”, 10, 20, 30);
(4)
ref.action(“(String, int, double)”,
10, 20.0);
(5)
ref.action(“(String, int, String)”,
10, “what?”);
(6)
ref.action(“(String, boolean)”,
false);
(6)
}
}

// (8)

calls

// (9)

calls

// (10) calls
// (11) calls
// (12) calls
// (13) calls
// (14) calls
// (15) calls
// (16) calls
// (17) calls

Output from the program (with remarks to the output on the right):
Click here to view code image
(String)
(String,
(String,
(String,
(String,
(String,
(String,
(String,
(String,
(String,

=> (String)
int) => (String, int)
Integer) => (String, int)
int, byte) => (String, int, int)
int, int) => (String, int, int)
int, long) => (String, Number[])
int, int, int) => (String, Integer[])
int, double) => (String, Number[])
int, String) => (String, Object[])
boolean) => (String, Object[])

7.11 Reference Casting and the

(8) calls (1)
(9) calls (2)
(10) calls (2)
(11) calls (3)
(12) calls (3)
(13) calls (5)
(14) calls (4)
(15) calls (5)
(16) calls (6)
(17) calls (6)

Operator

The Cast Operator
The type cast expression for reference types has the following syntax:
Click here to view code image

(destination_type) reference_expression
where the reference expression evaluates to a reference value of an object of some
reference type. A type cast expression checks that the reference value refers to an object
whose type is compatible with the destination type, meaning that its type is a subtype of
the destination type. The construct (destination_type) is usually called the cast operator.
The result of a type cast expression for references is always a reference value of an object.
WOW! eBook
www.wowebook.org

The literal null can be cast to any reference type.
The next code snippet illustrates the various scenarios that arise when using the cast
operator. In this discussion, it is the type cast expression that is important, not the
evaluation of the assignment operator in the declaration statements. In (1), the cast is from
the superclass Object to the subclass String; the code compiles and at runtime this
cast is permitted, as the reference obj will denote an object of class String. In (2), the
cast is from the superclass Object to the subclass Integer; the code compiles, but at
runtime this cast results in a ClassCastException, since the reference obj will
denote an object of class String, which cannot be converted to an Integer. In (3), the
cast is from the class String to the class Integer. As these two classes are unrelated,
the compiler flags an error for the cast.
Click here to view code image
Object obj = new String(“Cast me!”);
String str = (String) obj;
// (1) Cast from Object to String.
Integer iRef1 = (Integer) obj;
// (2) Cast from Object to Integer, but
//
ClassCastException at runtime.
Integer iRef2 = (Integer) str;
// (3) Compile-time error!
//
Cast between unrelated types.

The following conversions can be applied to the operand of a cast operator:
• Both widening and narrowing reference conversions, followed optionally by an
unchecked conversion
• Both boxing and unboxing conversions
Boxing and unboxing conversions that can occur during casting are illustrated by the
following code. Again, it is the type cast expression that is important in this discussion,
rather than whether the assignment operator requires one in the declaration statements.
Click here to view code image
// (1)
Number
// (2)
Object
// (3)
double

Boxing and casting: Number <— Integer <— int:
num = (Number) 100;
Casting, boxing, casting: Object <— Integer <— int <— double:
obj = (Object) (int) 10.5;
Casting, unboxing, casting: double <– int <— Integer <— Object:
d = (double) (Integer) obj;

Note that the resulting object in (1) and (2) is an Integer, but the resulting value in (3)
is a double. The boxing conversions from int to Integer in (1) and (2) are implicit,
and the unboxing conversion from Integer to int in (3) is also implicit.

The

Operator

The binary instanceof operator can be used for comparing types. It has the following
syntax (note that the keyword is composed of lowercase letters only):
Click here to view code image

reference_expression instanceof destination_type
The instanceof operator returns true if the left-hand operand (i.e., the reference
value that results from the evaluation of reference expression) can be a subtype of the
WOW! eBook
www.wowebook.org

right-hand operand (destination_type). It always returns false if the left-hand operand is
null. If the instanceof operator returns true, the corresponding type cast
expression will always be valid. Both the type cast expression and the instanceof
operators require a compile-time check and a runtime check, as explained later in this
section.
The compile-time check determines whether there is a subtype–supertype relationship
between the source and destination types. Given that the type of the reference expression
is source type, the compiler determines whether a reference of source type and a reference
of destination type can refer to objects of a reference type that are a common subtype of
both source type and destination type in the type hierarchy. If this is not the case, then
obviously there is no relationship between the types, and neither the cast nor the
instanceof operator application would be valid. At runtime, the reference expression
evaluates to a reference value of an object. It is the type of the actual object that
determines the outcome of the operation, as explained earlier.
With the classes Light and String as source type and destination type, respectively,
there is no subtype–supertype relationship between source type and destination type. The
compiler would reject casting a reference of type Light to type String or applying the
instanceof operator, as shown at (2) and (3) in Example 7.16. References of the
classes Light and TubeLight can refer to objects of the class TubeLight (or its
subclasses) in the inheritance hierarchy depicted in Figure 7.1. Therefore, it makes sense
to apply the instanceof operator or cast a reference of the type Light to the type
TubeLight as shown at (4) and (5), respectively, in Example 7.16.
At runtime, the result of applying the instanceof operator at (4) is false, because
the reference light1 of the class Light will actually denote an object of the subclass
LightBulb, and this object cannot be denoted by a reference of the peer class
TubeLight. Applying the cast at (5) results in a ClassCastException for the same
reason. This is the reason why cast conversions are said to be unsafe, as they may throw a
ClassCastException at runtime. Note that if the result of the instanceof
operator is false, the cast involving the operands will throw a
ClassCastException.
In Example 7.16, the result of applying the instanceof operator at (6) is also false,
because the reference light1 will still denote an object of the class LightBulb, whose
objects cannot be denoted by a reference of its subclass SpotLightBulb. Thus
applying the cast at (7) causes a ClassCastException to be thrown at runtime.
The situation shown at (8), (9), and (10) illustrates typical usage of the instanceof
operator to determine which object a reference is denoting, so that it can be cast for the
purpose of carrying out some specific action. The reference light1 of the class Light
is initialized to an object of the subclass NeonLight at (8). The result of the
instanceof operator at (9) is true, because the reference light1 will denote an
object of the subclass NeonLight, whose objects can also be denoted by a reference of
its superclass TubeLight. By the same token, the cast at (10) is valid. If the result of the
WOW! eBook
www.wowebook.org

instanceof operator is true, the cast involving the operands will be valid as well.
Example 7.16

The instanceof and Cast Operators

Click here to view code image
// See Figure 7.1, p. 267, for inheritance hierarchy.
class Light { /* … */ }
class LightBulb extends Light { /* … */ }
class SpotLightBulb extends LightBulb { /* … */ }
class TubeLight extends Light { /* … */ }
class NeonLight extends TubeLight { /* … */ }
public class WhoAmI {
public static void main(String[] args) {
boolean result1, result2, result3;
Light light1 = new LightBulb();
// String str = (String) light1;
error!
// result1 = light1 instanceof String;
error!
result2 = light1 instanceof TubeLight;
class.
// TubeLight tubeLight1 = (TubeLight) light1;
ClassCastException!

// (1)
// (2) Compile-time
// (3) Compile-time

// (4) false: peer
// (5)

result3 = light1 instanceof SpotLightBulb;
// (6) false:
superclass.
// SpotLightBulb spotRef = (SpotLightBulb) light1;// (7)
ClassCastException!
light1 = new NeonLight();
// (8)
if (light1 instanceof TubeLight) {
// (9) true.
TubeLight tubeLight2 = (TubeLight) light1;
// (10) OK.
// Can now use tubeLight2 to access an object of the class NeonLight,
// but only those members that the object inherits or overrides
// from the class TubeLight.
}
}
}

As we have seen, the instanceof operator effectively determines whether the reference
value in the reference on the left-hand side refers to an object whose class is a subtype of
the type of the reference specified on the right-hand side. At runtime, it is the type of the
actual object denoted by the reference on the left-hand side that is compared with the type
specified on the right-hand side. In other words, what matters at runtime is the type of the
actual object denoted by the reference, not the declared type of the reference.
Example 7.17 provides more examples of the instanceof operator. It is instructive to
go through the print statements and understand why those results printed out. The literal
null is not an instance of any reference type, as shown in the print statements at (1), (2),
and (16). An instance of a superclass is not an instance of its subclass, as shown in the
print statement at (4). An instance of a class is not an instance of a totally unrelated class,
as shown in the print statement at (10). An instance of a class is not an instance of an
interface type that the class does not implement, as shown in the print statement at (6).
Any array of non-primitive type is an instance of both Object and Object[] types, as
WOW! eBook
www.wowebook.org

shown in the print statements at (14) and (15), respectively.
Example 7.17

Using the instanceof Operator

Click here to view code image
// See Figure 7.3, p. 295, for inheritance
interface IStack
{ /*
interface ISafeStack extends IStack
{ /*
class StackImpl implements IStack
{ /*
class SafeStackImpl extends StackImpl
implements ISafeStack
{ /*

hierarchy.
From Example 7.7 */ }
From Example 7.7 */ }
From Example 7.7 */ }
From Example 7.7 */ }

public class Identification {
public static void main(String[] args) {
Object obj = new Object();
StackImpl stack = new StackImpl(10);
SafeStackImpl safeStack = new SafeStackImpl(5);
IStack iStack;
String strFormat = “(%d) %-25s instance of %-25s: %s%n”;
System.out.printf(strFormat, 1,
null, Object.class,
null instanceof Object);
// Always false.
System.out.printf(strFormat, 2,
null, IStack.class,
null instanceof IStack);
// Always false.
System.out.printf(strFormat, 3,
stack.getClass(), Object.class,
stack instanceof Object);
// true: instance of subclass of
Object.
System.out.printf(strFormat, 4,
obj.getClass(), StackImpl.class,
obj instanceof StackImpl);
// false: Object not subtype of
StackImpl.
System.out.printf(strFormat, 5,
stack.getClass(), StackImpl.class,
stack instanceof StackImpl); // true: instance of StackImpl.
System.out.printf(strFormat, 6,
obj.getClass(), IStack.class,
obj instanceof IStack);
// false: Object does not implement
IStack.
System.out.printf(strFormat, 7,
safeStack.getClass(), IStack.class,
safeStack instanceof IStack); // true: SafeStackImpl implements
IStack.
obj = stack;
// No cast required: assigning subclass to
superclass.
System.out.printf(strFormat, 8,
obj.getClass(), StackImpl.class,
obj instanceof StackImpl);
// true: instance of StackImpl.
System.out.printf(strFormat, 9,
obj.getClass(), IStack.class,
obj instanceof IStack);
// true: StackImpl implements IStack.
System.out.printf(strFormat, 10,
obj.getClass(), String.class,
obj instanceof String);
// false: no relationship.
iStack = (IStack) obj; // Cast required: assigning superclass to
WOW! eBook
www.wowebook.org

subclass.
System.out.printf(strFormat, 11,
iStack.getClass(), Object.class,
iStack instanceof Object);
// true: instance of subclass of
Object.
System.out.printf(strFormat, 12,
iStack.getClass(), StackImpl.class,
iStack instanceof StackImpl); // true: instance of StackImpl.
String[] strArray = new String[10];
// System.out.printf(strFormat, 13,
//
strArray.getClass(), String.class,
//
strArray instanceof String);
// Compile-time error: no
relationship.
System.out.printf(strFormat, 14,
strArray.getClass(), Object.class,
strArray instanceof Object);
// true: array subclass of Object.
System.out.printf(strFormat, 15,
strArray.getClass(), Object[].class,
strArray instanceof Object[]);
// true: array subclass of Object[].
System.out.printf(strFormat, 16,
strArray[0], Object.class,
strArray[0] instanceof Object); // false: strArray[0] is null.
System.out.printf(strFormat, 17,
strArray.getClass(), String[].class,
strArray instanceof String[]);
// true: array of String.
strArray[0] = “Amoeba strip”;
System.out.printf(strFormat, 18,
strArray[0].getClass(), String.class,
strArray[0] instanceof String); // true: strArray[0] instance of
String.
}
}

Output from the program:
Click here to view code image
(1)
(2)
(3)
(4)
(5)
(6)
(7)
(8)
(9)
(10)
(11)
(12)
(14)
(15)
(16)
(17)
(18)

null
instance of class java.lang.Object
: false
null
instance of interface IStack
: false
class StackImpl
instance of class java.lang.Object
: true
class java.lang.Object
instance of class StackImpl
: false
class StackImpl
instance of class StackImpl
: true
class java.lang.Object
instance of interface IStack
: false
class SafeStackImpl
instance of interface IStack
: true
class StackImpl
instance of class StackImpl
: true
class StackImpl
instance of interface IStack
: true
class StackImpl
instance of class java.lang.String
: false
class StackImpl
instance of class java.lang.Object
: true
class StackImpl
instance of class StackImpl
: true
class [Ljava.lang.String; instance of class java.lang.Object
: true
class [Ljava.lang.String; instance of class [Ljava.lang.Object;: true
null
instance of class java.lang.Object
: false
class [Ljava.lang.String; instance of class [Ljava.lang.String;: true
class java.lang.String
instance of class java.lang.String
: true

Review Questions
7.23 Which statement about the following program is true?
WOW! eBook
www.wowebook.org

Click here to view code image
public class MyClass {
public static void main(String[] args) {
A[] arrA;
B[] arrB;
arrA
arrB
arrA
arrB
arrA
arrB

=
=
=
=
=
=

new A[10];
new B[20];
arrB;
// (1)
(B[]) arrA; // (2)
new A[10];
(B[]) arrA; // (3)

}
}
class A {}
class B extends A {}

Select the one correct answer.
(a) The program will fail to compile because of the assignment at (1).
(b) When run, the program will throw a java.lang.ClassCastException
in the assignment at (2).
(c) When run, the program will throw a java.lang.ClassCastException
in the assignment at (3).
(d) The program will compile and run without errors, even if the cast operator
(B[]) in the statements at (2) and (3) is removed.
(e) The program will compile and run without errors, but will not do so if the cast
operator (B[]) in statements at (2) and (3) is removed.
7.24 Which statements will cause a compile-time error in the following code?
Click here to view code image
public class MyClass {
public static void main(String[] args) {
MyClass a;
MySubclass b;
a = new MyClass();
b = new MySubclass();

// (1)
// (2)

a = b;
b = a;

// (3)
// (4)

a = new MySubclass();
b = new MyClass();

// (5)
// (6)

}
}
class MySubclass extends MyClass {}

Select the two correct answers.
(a) (1)
(b) (2)
WOW! eBook
www.wowebook.org

(c) (3)
(d) (4)
(e) (5)
(f) (6)
7.25 Given the following type and reference declarations, which assignment is legal?
Click here to view code image
// Type declarations:
interface I1 {}
interface I2 {}
class C1 implements I1 {}
class C2 implements I2 {}
class C3 extends C1 implements I2 {}
// Reference declarations:
C1 obj1 = null;
C2 obj2 = null;
C3 obj3 = null;

Select the one correct answer.
(a) obj2 = obj1;
(b) obj3 = obj1;
(c) obj3 = obj2;
(d) I1 a = obj2;
(e) I1 b = obj3;
(f) I2 c = obj1;
7.26 Given the following class and reference declarations, what can be said about the
statement y = (Sub) x?
// Class declarations:
class Super {}
class Sub extends Super {}
// Reference declarations:
Super x = null;
Sub y = null;

Select the one correct answer.
(a) It is illegal at compile time.
(b) It is legal at compile time, but might be illegal at runtime.
(c) It is definitely legal at runtime, but the cast operator (Sub) is not strictly
needed.
(d) It is definitely legal at runtime, and the cast operator (Sub) is needed.
7.27 Given three classes A, B, and C, where B is a subclass of A, and C is a subclass of
B, which one of these boolean expressions is true only when the reference o
WOW! eBook
www.wowebook.org

refers to an object of class B, and not to an object of class A or class C?
Select the one correct answer.
(a) (o instanceof B) && (!(o instanceof A))
(b) (o instanceof B) && (!(o instanceof C))
(c) !((o instanceof A) || (o instanceof B))
(d) (o instanceof B)
(e) (o instanceof B) && !((o instanceof A) || (o
instanceof C))
7.28 What will the following program print when run?
Click here to view code image
public class RQ07A100 {
public static void main(String[] args) {
I x = new D();
if (x instanceof I) System.out.print(“I”);
if (x instanceof J) System.out.print(“J”);
if (x instanceof C) System.out.print(“C”);
if (x instanceof D) System.out.print(“D”);
System.out.println();
}
}
interface I{}
interface J{}
class C implements I {}
class D extends C implements J {}

Select the one correct answer.
(a) The program will not print any letters.
(b) ICD
(c) IJD
(d) IJCD
(e) ID
7.29 What is the result of compiling and running the following program?
Click here to view code image
class YingYang {
void yingyang(Integer i) {
System.out.println(“Integer: ” + i);
}
void yingyang(Integer[] ints) {
System.out.println(“Integer[]: ” + ints[0]);
}
void yingyang(Integer… ints) {
System.out.println(“Integer…: ” + ints[0]);
}
}
WOW! eBook
www.wowebook.org

public class RQ800A50 {
public static void main(String[] args) {
YingYang yy = new YingYang();
yy.yingyang(10);
yy.yingyang(10,12);
yy.yingyang(new Integer[] {10, 20});
yy.yingyang(new Integer(10), new Integer(20));
}
}

Select the one correct answer.
(a) The program will not compile because of errors.
(b) The program will compile, but throw an exception at runtime.
(c) The program will compile and print:
Integer: 10
Integer…: 10
Integer…: 10
Integer…: 10

(d) The program will compile and print:
Integer: 10
Integer…: 10
Integer[]: 10
Integer…: 10

7.30 What will be the result of compiling and running the following program?
Click here to view code image
public class RQ800A20 {
static void compute(int… ia) {
System.out.print(“|”);
for(int i : ia) {
System.out.print(i + “|”);
}
System.out.println();
}
static void compute(int[] ia1, int… ia2) {
compute(ia1);
compute(ia2);
}
static void compute(int[] ia1, int[]… ia2d) {
for(int[] ia : ia2d) {
compute(ia);
}
}
public static void main(String[] args) {
compute(new int[] {10, 11}, new int[] {12, 13, 14});
compute(15, 16);
compute(new int[] {17, 18}, new int[][] {{19}, {20}});
compute(null, new int[][] {{21}, {22}});
}
}

// (1)

// (2)

// (3)

//
//
//
//

(4)
(5)
(6)
(7)

Select the one correct answer.
(a) The program does not compile because of errors in one or more calls to the
compute() method.
WOW! eBook
www.wowebook.org

(b) The program compiles, but throws a NullPointerException when run.
(c) The program compiles and prints:
|10|11|
|12|13|14|
|15|16|
|19|
|20|
|21|
|22|

(d) The program compiles and prints:
|12|13|14|
|15|16|
|10|11|
|19|
|20|
|21|
|22|

7.12 Polymorphism and Dynamic Method Lookup
Which object a reference will actually denote during runtime cannot always be determined
at compile time. Polymorphism allows a reference to denote objects of different types at
different times during execution. A supertype reference exhibits polymorphic behavior
since it can denote objects of its subtypes.
When a non-private instance method is invoked on an object, the method definition
actually executed is determined both by the type of the object at runtime and by the
method signature. Dynamic method lookup (also known as late binding, dynamic binding,
and virtual method invocation) is the process of determining which method definition a
method signature denotes during runtime, based on the type of the object. However, a call
to a private instance method is not polymorphic. Such a call can occur only within the
class and gets bound to the private method implementation at compile time.
The inheritance hierarchy depicted in Figure 7.6 is implemented in Example 7.18. The
implementation of the method draw() is overridden in all subclasses of the class
Shape. The invocation of the draw() method in the two loops at (3) and (4) in Example
7.18 relies on the polymorphic behavior of references and dynamic method lookup. The
array shapes holds Shape references denoting a Circle, a Rectangle, and a
Square, as shown at (1). At runtime, dynamic lookup determines the draw()
implementation that will execute, based on the type of the object denoted by each element
in the array. This is also the case for the elements of the array drawables at (2), which
holds IDrawable references that can be assigned the reference value of any object of a
class that implements the IDrawable interface. The first loop will still work without any
change if objects of new subclasses of the class Shape are added to the array shapes. If
they did not override the draw() method, an inherited version of the method would be
executed. This polymorphic behavior applies to the array drawables, where the subtype
objects are guaranteed to have implemented the IDrawable interface.

WOW! eBook
www.wowebook.org

Figure 7.6

Type Hierarchy That Illustrates Polymorphism

Polymorphism and dynamic method lookup form a powerful programming paradigm that
simplifies client definitions, encourages object decoupling, and supports dynamically
changing relationships between objects at runtime.

WOW! eBook
www.wowebook.org

Example 7.18

Polymorphism and Dynamic Method Lookup

Click here to view code image
// File: PolymorphRefs.java
interface IDrawable {
void draw();
}
//_______________________________________________________________________________
class Shape implements IDrawable {
@Override public void draw() { System.out.println(“Drawing a Shape.”); }
}
//_______________________________________________________________________________
class Circle extends Shape {
@Override public void draw() { System.out.println(“Drawing a Circle.”); }
}
//_______________________________________________________________________________
class Rectangle extends Shape {
@Override public void draw() { System.out.println(“Drawing a Rectangle.”);
}
}
//_______________________________________________________________________________
class Square extends Rectangle {
@Override public void draw() { System.out.println(“Drawing a Square.”); }
}
//_______________________________________________________________________________
class Graph implements IDrawable {
@Override public void draw() { System.out.println(“Drawing a Graph.”); }
}
//_______________________________________________________________________________
public class PolymorphRefs {
public static void main(String[] args) {
Shape[] shapes = {new Circle(), new Rectangle(), new Square()};
//
(1)
IDrawable[] drawables = {new Shape(), new Rectangle(), new Graph()}; //
(2)
System.out.println(“Draw shapes:”);
for (Shape shape : shapes)

//

(3)
shape.draw();
System.out.println(“Draw drawables:”);
for (IDrawable drawable : drawables)
(4)
drawable.draw();
}
}

Output from the program:
Draw shapes:
Drawing a Circle.
Drawing a Rectangle.
Drawing a Square.
Draw drawables:
Drawing a Shape.
Drawing a Rectangle.
Drawing a Graph.

WOW! eBook
www.wowebook.org

//

7.13 Inheritance versus Aggregation
Figure 7.7 is a UML class diagram showing several aggregation relationships and one
inheritance relationship. This class diagram shows a queue defined by aggregation and a
stack defined by inheritance, both of which are based on linked lists. A linked list, in turn,
is defined by aggregation. Example 7.19 shows a non-generic implementation of these
data structures. The purpose of the example is to illustrate inheritance and aggregation, not
industrial-strength implementation of queues and stacks. The class Node at (1) is
straightforward, defining two fields: one denoting the data and the other denoting the next
node in the list. The class LinkedList at (2) keeps track of the list by managing head
and tail references. Nodes can be inserted in the front or back, but deleted only from the
front of the list.

Figure 7.7
Example 7.19

Implementing Data Structures by Inheritance and Aggregation

Implementing Data Structures by Inheritance and Aggregation

Click here to view code image
class Node {
private Object data;
private Node
next;

// (1)
// Data
// Next node

// Constructor for initializing data and reference to the next node.
Node(Object data, Node next) {
this.data = data;
this.next = next;
}
// Methods:
public void
public Object
public void
public Node

setData(Object obj)
getData()
setNext(Node node)
getNext()

{
{
{
{

data =
return
next =
return

obj; }
data; }
node; }
next; }

}
//______________________________________________________________________________
class LinkedList {
// (2)
protected Node head = null;
protected Node tail = null;
// Methods:
public boolean isEmpty() { return head == null; }
public void insertInFront(Object dataObj) {
if (isEmpty()) head = tail = new Node(dataObj, null);
WOW! eBook
www.wowebook.org

else head = new Node(dataObj, head);
}
public void insertAtBack(Object dataObj) {
if (isEmpty())
head = tail = new Node(dataObj, null);
else {
tail.setNext(new Node(dataObj, null));
tail = tail.getNext();
}
}
public Object deleteFromFront() {
if (isEmpty()) return null;
Node removed = head;
if (head == tail) head = tail = null;
else head = head.getNext();
return removed.getData();
}
}
//______________________________________________________________________________
class QueueByAggregation {
// (3)
private LinkedList qList;
// Constructor
QueueByAggregation() {
qList = new LinkedList();
}
// Methods:
public boolean isEmpty() { return qList.isEmpty(); }
public void enqueue(Object item) { qList.insertAtBack(item); }
public Object dequeue() {
if (qList.isEmpty()) return null;
return qList.deleteFromFront();
}
public Object peek() {
return (qList.isEmpty() ? null : qList.head.getData());
}
}
//______________________________________________________________________________
class StackByInheritance extends LinkedList {
// (4)
public void push(Object item) { insertInFront(item); }
public Object pop() {
if (isEmpty()) return null;
return deleteFromFront();
}
public Object peek() {
return (isEmpty() ? null : head.getData());
}
}
//______________________________________________________________________________
public class Client {
// (5)
public static void main(String[] args) {
String string1 = “Queues are boring to stand in!”;
int length1 = string1.length();
QueueByAggregation queue = new QueueByAggregation();
for (int i = 0; i