[Ebooks PDF] download Data Structures and Algorithms in Java 6th Edition Michael T. Goodrich full chapters
[Ebooks PDF] download Data Structures and Algorithms in Java 6th Edition Michael T. Goodrich full chapters
com
https://ebookultra.com/download/data-structures-
and-algorithms-in-java-6th-edition-michael-t-
goodrich/
https://ebookultra.com/download/data-structures-and-algorithms-in-
java-4th-edition-michael-t-goodrich/
ebookultra.com
https://ebookultra.com/download/ai-algorithms-data-structures-and-
idioms-in-prolog-lisp-and-java-6th-edition-george-f-luger/
ebookultra.com
https://ebookultra.com/download/java-collections-an-introduction-to-
abstract-data-types-data-structures-and-algorithms-1st-edition-david-
a-watt/
ebookultra.com
https://ebookultra.com/download/data-structures-algorithms-in-go-1st-
edition-hemant-jain/
ebookultra.com
Growing Algorithms and Data Structures 4th Edition David
Scuse
https://ebookultra.com/download/growing-algorithms-and-data-
structures-4th-edition-david-scuse/
ebookultra.com
https://ebookultra.com/download/learning-javascript-data-structures-
and-algorithms-2nd-edition-loiane-groner/
ebookultra.com
https://ebookultra.com/download/learning-f-functional-data-structures-
and-algorithms-1st-edition-masood/
ebookultra.com
https://ebookultra.com/download/concise-notes-on-data-structures-and-
algorithms-ruby-edition-christopher-fox/
ebookultra.com
https://ebookultra.com/download/data-structures-and-algorithms-using-
python-1st-edition-rance-d-necaise/
ebookultra.com
Data Structures and Algorithms in Java 6th Edition
Michael T. Goodrich Digital Instant Download
Author(s): Michael T. Goodrich, Roberto Tamassia, Michael H. Goldwasser
ISBN(s): 9781118771334, 1118771338
Edition: 6
File Details: PDF, 9.40 MB
Year: 2014
Language: english
Data Structures and
Algorithms in Java™
Sixth Edition
Michael T. Goodrich
Department of Computer Science
University of California, Irvine
Roberto Tamassia
Department of Computer Science
Brown University
Michael H. Goldwasser
Department of Mathematics and Computer Science
Saint Louis University
Vice President and Executive Publisher Don Fowley
Executive Editor Beth Lang Golub
Assistant Marketing Manager Debbie Martin
Sponsoring Editor Mary O’Sullivan
Project Editor Ellen Keohane
Associate Production Manager Joyce Poh
Cover Designer Kenji Ngieng
This book was set in LATEX by the authors, and printed and bound by RR Donnelley. The
cover was printed by RR Donnelley.
Trademark Acknowledgments: Java is a trademark of Oracle Corporation. Unix ® is a
registered trademark in the United States and other countries, licensed through X/Open
Company, Ltd. PowerPoint ® is a trademark of Microsoft Corporation. All other product
names mentioned herein are the trademarks of their respective owners.
This book is printed on acid free paper.
Founded in 1807, John Wiley & Sons, Inc. has been a valued source of knowledge and
understanding for more than 200 years, helping people around the world meet their needs
and fulfill their aspirations. Our company is built on a foundation of principles that include
responsibility to the communities we serve and where we live and work. In 2008, we
launched a Corporate Citizenship Initiative, a global effort to address the environmental,
social, economic, and ethical challenges we face in our business. Among the issues we
are addressing are carbon impact, paper specifications and procurement, ethical conduct
within our business and among our vendors, and community and charitable support. For
more information, please visit our website: www.wiley.com/go/citizenship.
Copyright © 2014, 2010 John Wiley & Sons, Inc. All rights reserved. No part of this publi-
cation may be reproduced, stored in a retrieval system or transmitted in any form or by any
means, electronic, mechanical, photocopying, recording, scanning or otherwise, except
as permitted under Sections 107 or 108 of the 1976 United States Copyright Act, with-
out either the prior written permission of the Publisher, or authorization through payment
of the appropriate per-copy fee to the Copyright Clearance Center, Inc. 222 Rosewood
Drive, Danvers, MA 01923, website www.copyright.com. Requests to the Publisher for
permission should be addressed to the Permissions Department, John Wiley & Sons, Inc.,
111 River Street, Hoboken, NJ 07030-5774, (201) 748-6011, fax (201) 748-6008, website
http://www.wiley.com/go/ permissions.
Evaluation copies are provided to qualified academics and professionals for review pur-
poses only, for use in their courses during the next academic year. These copies are licensed
and may not be sold or transferred to a third party. Upon completion of the review period,
please return the evaluation copy to Wiley. Return instructions and a free of charge return
mailing label are available at www.wiley.com/go/returnlabel. If you have chosen to adopt
this textbook for use in your course, please accept this book as your complimentary desk
copy. Outside of the United States, please contact your local sales representative.
ISBN: 978-1-118-77133-4 (paperback)
Printed in the United States of America
10 9 8 7 6 5 4 3 2 1
To Karen, Paul, Anna, and Jack
– Michael T. Goodrich
To Isabel
– Roberto Tamassia
v
vi Preface
Prerequisites
We assume that the reader is at least vaguely familiar with a high-level program-
ming language, such as C, C++, Python, or Java, and that he or she understands the
main constructs from such a high-level language, including:
• Variables and expressions
• Methods (also known as functions or procedures)
• Decision structures (such as if-statements and switch-statements)
• Iteration structures (for-loops and while-loops)
For readers who are familiar with these concepts, but not with how they are ex-
pressed in Java, we provide a primer on the Java language in Chapter 1. Still, this
book is primarily a data structures book, not a Java book; hence, it does not provide
a comprehensive treatment of Java. Nevertheless, we do not assume that the reader
is necessarily familiar with object-oriented design or with linked structures, such
as linked lists, for these topics are covered in the core chapters of this book.
In terms of mathematical background, we assume the reader is somewhat famil-
iar with topics from high-school mathematics. Even so, in Chapter 4, we discuss
the seven most-important functions for algorithm analysis. In fact, sections that use
something other than one of these seven functions are considered optional, and are
indicated with a star (⋆).
Online Resources
This book is accompanied by an extensive set of online resources, which can be
found at the following website:
www.wiley.com/college/goodrich
Included on this website is a collection of educational aids that augment the topics
of this book, for both students and instructors. For all readers, and especially for
students, we include the following resources:
• All Java source code presented in this book
• An appendix of useful mathematical facts
• PDF handouts of PowerPoint slides (four-per-page)
• A study guide with hints to exercises, indexed by problem number
For instructors using this book, we include the following additional teaching aids:
• Solutions to hundreds of the book’s exercises
• Color versions of all figures and illustrations from the book
• Slides in PowerPoint and PDF (one-per-page) format
The slides are fully editable, so as to allow an instructor using this book full free-
dom in customizing his or her presentations.
Preface vii
Use as a Textbook
The design and analysis of efficient data structures has long been recognized as a
core subject in computing. We feel that the central role of data structure design and
analysis in the curriculum is fully justified, given the importance of efficient data
structures and algorithms in most software systems, including the Web, operating
systems, databases, compilers, and scientific simulation systems.
This book is designed for use in a beginning-level data structures course, or
in an intermediate-level introduction to algorithms course. The chapters for this
book are organized to provide a pedagogical path that starts with the basics of Java
programming and object-oriented design. We then discuss concrete structures in-
cluding arrays and linked lists, and foundational techniques like algorithm analysis
and recursion. In the main portion of the book we present fundamental data struc-
tures and algorithms, concluding with a discussion of memory management. A
detailed table of contents follows this preface, beginning on page x.
To assist instructors in designing a course in the context of the IEEE/ACM
2013 Computing Curriculum, the following table describes curricular knowledge
units that are covered within this book.
Acknowledgments
There are so many individuals who have made contributions to the development of
this book over the past decade, it is difficult to name them all. We wish to reit-
erate our thanks to the many research collaborators and teaching assistants whose
feedback shaped the previous versions of this material. The benefits of those con-
tributions carry forward to this book.
For the sixth edition, we are indebted to the outside reviewers and readers for
their copious comments, emails, and constructive criticisms. We therefore thank the
following people for their comments and suggestions: Sameer O. Abufardeh (North
Dakota State University), Mary Boelk (Marquette University), Frederick Crabbe
(United States Naval Academy), Scot Drysdale (Dartmouth College), David Eisner,
Henry A. Etlinger (Rochester Institute of Technology), Chun-Hsi Huang (Univer-
sity of Connecticut), John Lasseter (Hobart and William Smith Colleges), Yupeng
Lin, Suely Oliveira (University of Iowa), Vincent van Oostrom (Utrecht Univer-
sity), Justus Piater (University of Innsbruck), Victor I. Shtern (Boston University),
Tim Soethout, and a number of additional anonymous reviewers.
There have been a number of friends and colleagues whose comments have led
to improvements in the text. We are particularly thankful to Erin Chambers, Karen
Goodrich, David Letscher, David Mount, and Ioannis Tollis for their insightful
comments. In addition, contributions by David Mount to the coverage of recursion
and to several figures are gratefully acknowledged.
We appreciate the wonderful team at Wiley, including our editor, Beth Lang
Golub, for her enthusiastic support of this project from beginning to end, and the
Product Solutions Group editors, Mary O’Sullivan and Ellen Keohane, for carrying
the project to its completion. The quality of this book is greatly enhanced as a result
of the attention to detail demonstrated by our copyeditor, Julie Kennedy. The final
months of the production process were gracefully managed by Joyce Poh.
Finally, we would like to warmly thank Karen Goodrich, Isabel Cruz, Susan
Goldwasser, Giuseppe Di Battista, Franco Preparata, Ioannis Tollis, and our parents
for providing advice, encouragement, and support at various stages of the prepa-
ration of this book, and Calista and Maya Goldwasser for offering their advice
regarding the artistic merits of many illustrations. More importantly, we thank all
of these people for reminding us that there are things in life beyond writing books.
Michael T. Goodrich
Roberto Tamassia
Michael H. Goldwasser
Contents
1 Java Primer 1
1.1 Getting Started . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.1.1 Base Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2 Classes and Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2.1 Creating and Using Objects . . . . . . . . . . . . . . . . . . . . 6
1.2.2 Defining a Class . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.3 Strings, Wrappers, Arrays, and Enum Types . . . . . . . . . . . . . 17
1.4 Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.4.1 Literals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
1.4.2 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1.4.3 Type Conversions . . . . . . . . . . . . . . . . . . . . . . . . . 28
1.5 Control Flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
1.5.1 The If and Switch Statements . . . . . . . . . . . . . . . . . . 30
1.5.2 Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
1.5.3 Explicit Control-Flow Statements . . . . . . . . . . . . . . . . . 37
1.6 Simple Input and Output . . . . . . . . . . . . . . . . . . . . . . . . 38
1.7 An Example Program . . . . . . . . . . . . . . . . . . . . . . . . . . 41
1.8 Packages and Imports . . . . . . . . . . . . . . . . . . . . . . . . . . 44
1.9 Software Development . . . . . . . . . . . . . . . . . . . . . . . . . 46
1.9.1 Design . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
1.9.2 Pseudocode . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
1.9.3 Coding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
1.9.4 Documentation and Style . . . . . . . . . . . . . . . . . . . . . 50
1.9.5 Testing and Debugging . . . . . . . . . . . . . . . . . . . . . . 53
1.10 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
2 Object-Oriented Design 59
2.1 Goals, Principles, and Patterns . . . . . . . . . . . . . . . . . . . . 60
2.1.1 Object-Oriented Design Goals . . . . . . . . . . . . . . . . . . 60
2.1.2 Object-Oriented Design Principles . . . . . . . . . . . . . . . . 61
2.1.3 Design Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . 63
2.2 Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
2.2.1 Extending the CreditCard Class . . . . . . . . . . . . . . . . . . 65
2.2.2 Polymorphism and Dynamic Dispatch . . . . . . . . . . . . . . 68
2.2.3 Inheritance Hierarchies . . . . . . . . . . . . . . . . . . . . . . 69
2.3 Interfaces and Abstract Classes . . . . . . . . . . . . . . . . . . . . 76
2.3.1 Interfaces in Java . . . . . . . . . . . . . . . . . . . . . . . . . 76
2.3.2 Multiple Inheritance for Interfaces . . . . . . . . . . . . . . . . 79
2.3.3 Abstract Classes . . . . . . . . . . . . . . . . . . . . . . . . . . 80
2.4 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
2.4.1 Catching Exceptions . . . . . . . . . . . . . . . . . . . . . . . . 82
2.4.2 Throwing Exceptions . . . . . . . . . . . . . . . . . . . . . . . 85
2.4.3 Java’s Exception Hierarchy . . . . . . . . . . . . . . . . . . . . 86
2.5 Casting and Generics . . . . . . . . . . . . . . . . . . . . . . . . . . 88
x
Contents xi
2.5.1 Casting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
2.5.2 Generics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
2.6 Nested Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
2.7 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
5 Recursion 189
5.1 Illustrative Examples . . . . . . . . . . . . . . . . . . . . . . . . . . 191
5.1.1 The Factorial Function . . . . . . . . . . . . . . . . . . . . . . 191
5.1.2 Drawing an English Ruler . . . . . . . . . . . . . . . . . . . . . 193
5.1.3 Binary Search . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
xii Contents
5.1.4 File Systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
5.2 Analyzing Recursive Algorithms . . . . . . . . . . . . . . . . . . . . 202
5.3 Further Examples of Recursion . . . . . . . . . . . . . . . . . . . . . 206
5.3.1 Linear Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . 206
5.3.2 Binary Recursion . . . . . . . . . . . . . . . . . . . . . . . . . 211
5.3.3 Multiple Recursion . . . . . . . . . . . . . . . . . . . . . . . . 212
5.4 Designing Recursive Algorithms . . . . . . . . . . . . . . . . . . . . 214
5.5 Recursion Run Amok . . . . . . . . . . . . . . . . . . . . . . . . . . 215
5.5.1 Maximum Recursive Depth in Java . . . . . . . . . . . . . . . . 218
5.6 Eliminating Tail Recursion . . . . . . . . . . . . . . . . . . . . . . . 219
5.7 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
8 Trees 307
8.1 General Trees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 308
8.1.1 Tree Definitions and Properties . . . . . . . . . . . . . . . . . . 309
8.1.2 The Tree Abstract Data Type . . . . . . . . . . . . . . . . . . 312
8.1.3 Computing Depth and Height . . . . . . . . . . . . . . . . . . . 314
8.2 Binary Trees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
8.2.1 The Binary Tree Abstract Data Type . . . . . . . . . . . . . . . 319
8.2.2 Properties of Binary Trees . . . . . . . . . . . . . . . . . . . . 321
8.3 Implementing Trees . . . . . . . . . . . . . . . . . . . . . . . . . . . 323
8.3.1 Linked Structure for Binary Trees . . . . . . . . . . . . . . . . . 323
8.3.2 Array-Based Representation of a Binary Tree . . . . . . . . . . 331
8.3.3 Linked Structure for General Trees . . . . . . . . . . . . . . . . 333
8.4 Tree Traversal Algorithms . . . . . . . . . . . . . . . . . . . . . . . 334
8.4.1 Preorder and Postorder Traversals of General Trees . . . . . . . 334
8.4.2 Breadth-First Tree Traversal . . . . . . . . . . . . . . . . . . . 336
8.4.3 Inorder Traversal of a Binary Tree . . . . . . . . . . . . . . . . 337
8.4.4 Implementing Tree Traversals in Java . . . . . . . . . . . . . . 339
8.4.5 Applications of Tree Traversals . . . . . . . . . . . . . . . . . . 343
8.4.6 Euler Tours . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348
8.5 Exercises . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350
Bibliography 710
Index 714
1 Java Primer
Contents
Reserved Words
abstract default goto package synchronized
assert do if private this
boolean double implements protected throw
break else import public throws
byte enum instanceof return transient
case extends int short true
catch false interface static try
char final long strictfp void
class finally native super volatile
const float new switch while
continue for null
Table 1.1: A listing of the reserved words in Java. These names cannot be used as
class, method, or variable names.
Comments
We will intentionally color all comments in blue in this book, so that they are not
confused with executable code.
While inline comments are limited to one line, Java allows multiline comments
in the form of block comments. Java uses a “/*” to begin a block comment and a
“*/” to close it. For example:
/*
* This is a block comment.
*/
Block comments that begin with “/**” (note the second asterisk) have a special
purpose, allowing a program, called Javadoc, to read these comments and automat-
ically generate software documentation. We discuss the syntax and interpretation
of Javadoc comments in Section 1.9.4.
4 Chapter 1. Java Primer
For the most commonly used data types, Java provides the following base types
(also called primitive types):
A variable having one of these types simply stores a value of that type. Integer
constants, like 14 or 195, are of type int, unless followed immediately by an ‘L’
or ‘l’, in which case they are of type long. Floating-point constants, like 3.1416
or 6.022e23, are of type double, unless followed immediately by an ‘F’ or ‘f’, in
which case they are of type float. Code Fragment 1.1 demonstrates the declaration,
and initialization in some cases, of various base-type variables.
Note that it is possible to declare (and initialize) multiple variables of the same
type in a single statement, as done on lines 2, 6, and 9 of this example. In this code
fragment, variables verbose, debug, i, and j remain uninitialized. Variables declared
locally within a block of code must be initialized before they are first used.
A nice feature of Java is that when base-type variables are declared as instance
variables of a class (see next section), Java ensures initial default values if not ex-
plicitly initialized. In particular, all numeric types are initialized to zero, a boolean
is initialized to false, and a character is initialized to the null character by default.
1.2. Classes and Objects 5
This class includes one instance variable, named count, which is declared at
line 2. As noted on the previous page, the count will have a default value of zero,
unless we otherwise initialize it.
The class includes two special methods known as constructors (lines 3 and
4), one accessor method (line 5), and three update methods (lines 6–8). Unlike
the original Universe class from page 2, our Counter class does not have a main
method, and so it cannot be run as a complete program. Instead, the purpose of the
Counter class is to create instances that might be used as part of a larger program.
6 Chapter 1. Java Primer
Figure 1.2: Illustrating the relationship between objects and object reference vari-
ables. When we assign an object reference (that is, memory address) to a reference
variable, it is as if we are storing that object’s remote control at that variable.
There can, in fact, be many references to the same object, and each reference to
a specific object can be used to call methods on that object. Such a situation would
correspond to our having many remote controls that all work on the same device.
Any of the remotes can be used to make a change to the device (like changing a
channel on a television). Note that if one remote control is used to change the
device, then the (single) object pointed to by all the remotes changes. Likewise, if
one object reference variable is used to change the state of the object, then its state
changes for all the references to it. This behavior comes from the fact that there are
many references, but they all point to the same object.
Returning to our CounterDemo example, the instance constructed at line 9 as
Counter d = new Counter(5);
is a distinct instance from the one identified as c. However, the command at line 11,
Counter e = d;
does not result in the construction of a new Counter instance. This declares a new
reference variable named e, and assigns that variable a reference to the existing
counter instance currently identified as d. At that point, both variables d and e are
aliases for the same object, and so the call to d.getCount( ) behaves just as would
e.getCount( ). Similarly, the call to update method e.increment(2) is affecting the
same object identified by d.
It is worth noting, however, that the aliasing of two reference variables to the
same object is not permanent. At any point in time, we may reassign a reference
variable to a new instance, to a different existing instance, or to null.
1.2. Classes and Objects 9
Modifiers
Immediately before the definition of a class, instance variable, or method in Java,
keywords known as modifiers can be placed to convey additional stipulations about
that definition.
Declaring Methods
A method definition has two parts: the signature, which defines the name and
parameters for a method, and the body, which defines what the method does. The
method signature specifies how the method is called, and the method body specifies
what the object will do when it is called. The syntax for defining a method is as
follows:
[modifiers] returnType methodName(type1 param1 , . . . , typen paramn ) {
// method body . . .
}
Each of the pieces of this declaration has an important purpose. We have al-
ready discussed the significance of modifiers such as public, private, and static.
The returnType designation defines the type of value returned by the method. The
methodName can be any valid Java identifier. The list of parameters and their types
declares the local variables that correspond to the values that are to be passed as
arguments to this method. Each type declaration typei can be any Java type name
and each parami can be any distinct Java identifier. This list of parameters and
their types can be empty, which signifies that there are no values to be passed to
this method when it is invoked. These parameter variables, as well as the instance
variables of the class, can be used inside the body of the method. Likewise, other
methods of this class can be called from inside the body of a method.
When a (nonstatic) method of a class is called, it is invoked on a specific in-
stance of that class and can change the state of that object. For example, the follow-
ing method of the Counter class increases the counter’s value by the given amount.
public void increment(int delta) {
count += delta;
}
Notice that the body of this method uses count, which is an instance variable, and
delta, which is a parameter.
Return Types
A method definition must specify the type of value the method will return. If the
method does not return a value (as with the increment method of the Counter class),
then the keyword void must be used. To return a value in Java, the body of the
method must use the return keyword, followed by a value of the appropriate return
type. Here is an example of a method (from the Counter class) with a nonvoid
return type:
public int getCount( ) {
return count;
}
1.2. Classes and Objects 13
Java methods can return only one value. To return multiple values in Java, we
should instead combine all the values we want to return in a compound object,
whose instance variables include all the values we want to return, and then return a
reference to that compound object. In addition, we can change the internal state of
an object that is passed to a method as another way of “returning” multiple results.
Parameters
Defining Constructors
A constructor is a special kind of method that is used to initialize a newly created
instance of the class so that it will be in a consistent and stable initial state. This
is typically achieved by initializing each instance variable of the object (unless
the default value will suffice), although a constructor can perform more complex
computation. The general syntax for declaring a constructor in Java is as follows:
modifiers name(type0 parameter0 , . . . , typen−1 parametern−1 ) {
// constructor body . . .
}
Constructors are defined in a very similar way as other methods of a class, but there
are a few important distinctions:
1. Constructors cannot be static, abstract, or final, so the only modifiers that
are allowed are those that affect visibility (i.e., public, protected, private,
or the default package-level visibility).
2. The name of the constructor must be identical to the name of the class it
constructs. For example, when defining the Counter class, a constructor must
be named Counter as well.
3. We don’t specify a return type for a constructor (not even void). Nor does
the body of a constructor explicitly return anything. When a user of a class
creates an instance using a syntax such as
Counter d = new Counter(5);
the new operator is responsible for returning a reference to the new instance
to the caller; the responsibility of the constructor method is only to initialize
the state of the new instance.
A class can have many constructors, but each must have a different signature,
that is, each must be distinguished by the type and number of the parameters it
takes. If no constructors are explicitly defined, Java provides an implicit default
constructor for the class, having zero arguments and leaving all instance variables
initialized to their default values. However, if a class defines one or more nondefault
constructors, no default constructor will be provided.
As an example, our Counter class defines the following pair of constructors:
public Counter( ) { }
public Counter(int initial) { count = initial; }
The first of these has a trivial body, { }, as the goal for this default constructor is to
create a counter with value zero, and that is already the default value of the integer
instance variable, count. However, it is still important that we declared such an
explicit constructor, because otherwise none would have been provided, given the
existence of the nondefault constructor. In that scenario, a user would have been
unable to use the syntax, new Counter( ).
1.2. Classes and Objects 15
3. To allow one constructor body to invoke another constructor body. When one
method of a class invokes another method of that same class on the current
instance, that is typically done by using the (unqualified) name of the other
method. But the syntax for calling a constructor is special. Java allows use of
the keyword this to be used as a method within the body of one constructor,
so as to invoke another constructor with a different signature.
This is often useful because all of the initialization steps of one constructor
can be reused with appropriate parameterization. As a trivial demonstra-
tion of the syntax, we could reimplement the zero-argument version of our
Counter constructor to have it invoke the one-argument version sending 0 as
an explicit parameter. This would be written as follows:
public Counter( ) {
this(0); // invoke one-parameter constructor with value zero
}
We will provide a more meaningful demonstration of this technique in a later
example of a CreditCard class in Section 1.7.
16 Chapter 1. Java Primer
Unit Testing
When defining a class, such as Counter, that is meant to be used by other classes
rather than as a self-standing program, there is no need to define a main method.
However, a nice feature of Java’s design is that we could provide such a method
as a way to test the functionality of that class in isolation, knowing that it would
not be run unless we specifically invoke the java command on that isolated class.
However, for more robust testing, frameworks such as JUnit are preferred.
1.3. Strings, Wrappers, Arrays, and Enum Types 17
Character Indexing
Each character c within a string s can be referenced by using an index, which is
equal to the number of characters that come before c in s. By this convention, the
first character is at index 0, and the last is at index n − 1, where n is the length of the
string. For example, the string title, defined above, has length 36. The character at
index 2 is 't' (the third character), and the character at index 4 is ' ' (the space
character). Java’s String class supports a method length( ), which returns the length
of a string instance, and a method charAt(k), which returns the character at index k.
Concatenation
The primary operation for combining strings is called concatenation, which takes
a string P and a string Q combines them into a new string, denoted P + Q, which
consists of all the characters of P followed by all the characters of Q. In Java, the
“+” operation performs concatenation when acting on two strings, as follows:
String term = "over" + "load";
This statement defines a variable named term that references a string with value
"overload". (We will discuss assignment statements and expressions such as that
above in more detail later in this chapter.)
18 Chapter 1. Java Primer
An error condition occurs, for both String and StringBuilder classes, if an index k
is out of the bounds of the indices of the character sequence.
The StringBuilder class can be very useful, and it serves as an interesting case
study for data structures and algorithms. We will further explore the empirical ef-
ficiency of the StringBuilder class in Section 4.1 and the theoretical underpinnings
of its implementation in Section 7.2.4.
1.3. Strings, Wrappers, Arrays, and Enum Types 19
Wrapper Types
There are many data structures and algorithms in Java’s libraries that are specif-
ically designed so that they only work with object types (not primitives). To get
around this obstacle, Java defines a wrapper class for each base type. An instance
of each wrapper type stores a single value of the corresponding base type. In Ta-
ble 1.2, we show the base types and their corresponding wrapper class, along with
examples of how objects are created and accessed.
Table 1.2: Java’s wrapper classes. Each class is given with its corresponding base
type and example expressions for creating and accessing such objects. For each
row, we assume the variable obj is declared with the corresponding class name.
1 int j = 8;
2 Integer a = new Integer(12);
3 int k = a; // implicit call to a.intValue()
4 int m = j + a; // a is automatically unboxed before the addition
5 a = 3 ∗ m; // result is automatically boxed before assignment
6 Integer b = new Integer("-135"); // constructor accepts a String
7 int n = Integer.parseInt("2013"); // using static method of Integer class
Code Fragment 1.4: A demonstration of the use of the Integer wrapper class.
20 Chapter 1. Java Primer
Arrays
A common programming task is to keep track of an ordered sequence of related
values or objects. For example, we may want a video game to keep track of the top
ten scores for that game. Rather than using ten different variables for this task, we
would prefer to use a single name for the group and use index numbers to refer to
the high scores in that group. Similarly, we may want a medical information system
to keep track of the patients currently assigned to beds in a certain hospital. Again,
we would rather not have to introduce 200 variables in our program just because
the hospital has 200 beds.
In such cases, we can save programming effort by using an array, which is a
sequenced collection of variables all of the same type. Each variable, or cell, in an
array has an index, which uniquely refers to the value stored in that cell. The cells
of an array a are numbered 0, 1, 2, and so on. We illustrate an array of high scores
for a video game in Figure 1.3.
High
scores
indices
Figure 1.3: An illustration of an array of ten (int) high scores for a video game.
Arrays in Java are somewhat unusual, in that they are not technically a base type
nor are they instances of a particular class. With that said, an instance of an array is
treated as an object by Java, and variables of an array type are reference variables.
To declare a variable (or parameter) to have an array type, we use an empty
pair of square brackets just after the type of element that the array will store. For
example, we might declare:
int[ ] primes;
Because arrays are a reference type, this declares the variable primes to be a refer-
ence to an array of integer values, but it does not immediately construct any such
array. There are two ways for creating an array.
The first way to create an array is to use an assignment to a literal form when
initially declaring the array, using a syntax as:
elementType[ ] arrayName = {initialValue0 , initialValue1 , . . . , initialValue N−1 };
The elementType can be any Java base type or class name, and arrayName can be
any valid Java identifier. The initial values must be of the same type as the array.
For example, we could initialize the array of primes to contain the first ten prime
numbers as:
int[ ] primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
When using an initializer, an array is created having precisely the capacity needed
to store the indicated values.
The second way to create an array is to use the new operator. However, because
an array is not an instance of a class, we do not use a typical constructor syntax.
Instead we use the syntax:
new elementType[length]
where length is a positive integer denoting the length of the new array. The new
operator returns a reference to the new array, and typically this would be assigned to
an array variable. For example, the following statement declares an array variable
named measurements, and immediately assigns it a new array of 1000 cells.
double[ ] measurements = new double[1000];
When arrays are created using the new operator, all of their elements are au-
tomatically assigned the default value for the element type. That is, if the element
type is numeric, all cells of the array are initialized to zero, if the element type is
boolean, all cells are false, and if the element type is a reference type (such as with
an array of String instances), all cells are initialized to null.
22 Chapter 1. Java Primer
Enum Types
In olden times, programmers would often define a series of constant integer values
to be used for representing a finite set of choices. For example, in representing a
day of the week, they might declare variable today as an int and then set it with
value 0 for Monday, 1 for Tuesday, and so on.
A slightly better programming style is to define static constants (with the final
keyword), to make the associations, such as:
static final int MON = 0;
static final int TUE = 1;
static final int WED = 2;
...
because then it becomes possible to make assignments such as today = TUE,
rather than the more obscure today = 1. Unfortunately, the variable today is still
declared as an int using such a programming style, and it may not be clear that you
intend for it to represent a day of the week when storing it as an instance variable
or sending it as a parameter.
Java supports a more elegant approach to representing choices from a finite
set by defining what is known as an enumerated type, or enum for short. These
are types that are only allowed to take on values that come from a specified set of
names. They are declared as follows:
where the modifier can be blank, public, protected, or private. The name of
this enum, name, can be any legal Java identifier. Each of the value identifiers,
valueNamei , is the name of a possible value that variables of this enum type can
take on. Each of these name values can also be any legal Java identifier, but the
Java convention is that these should usually be capitalized words. For example, an
enumerated type definition for days of the weak might appear as:
public enum Day { MON, TUE, WED, THU, FRI, SAT, SUN };
Once defined, Day becomes an official type and we may declare variables or pa-
rameters with type Day. A variable of that type can be declared as:
Day today;
and an assignment of a value to that variable can appear as:
today = Day.TUE;
1.4. Expressions 23
1.4 Expressions
Variables and constants are used in expressions to define new values and to modify
variables. In this section, we discuss how expressions work in Java in more detail.
Expressions involve the use of literals, variables, and operators. Since we have al-
ready discussed variables, let us briefly focus on literals and then discuss operators
in some detail.
1.4.1 Literals
A literal is any “constant” value that can be used in an assignment or other expres-
sion. Java allows the following kinds of literals:
• The null object reference (this is the only object literal, and it is allowed to
be any reference type).
• Boolean: true and false.
• Integer: The default for an integer like 176, or -52 is that it is of type int,
which is a 32-bit integer. A long integer literal must end with an “L” or “l”,
for example, 176L or -52l, and defines a 64-bit integer.
• Floating Point: The default for floating-point numbers, such as 3.1415 and
135.23, is that they are double. To specify that a literal is a float, it must
end with an “F” or “f”. Floating-point literals in exponential notation are also
allowed, such as 3.14E2 or .19e10; the base is assumed to be 10.
• Character: In Java, character constants are assumed to be taken from the
Unicode alphabet. Typically, a character is defined as an individual symbol
enclosed in single quotes. For example, ’a’ and ’?’ are character constants.
In addition, Java defines the following special character constants:
1.4.2 Operators
Java expressions involve composing literals and variables with operators. We will
survey the operators in Java in this section.
Arithmetic Operators
The following are binary arithmetic operators in Java:
+ addition
− subtraction
∗ multiplication
/ division
% the modulo operator
This last operator, modulo, is also known as the “remainder” operator, because
it is the remainder left after an integer division. We often use “ mod ” to denote the
modulo operator, and we define it formally as
n mod m = r,
such that
n = mq + r,
for an integer q and 0 ≤ r < m.
Java also provides a unary minus (−), which can be placed in front of an arith-
metic expression to invert its sign. Parentheses can be used in any expression to
define the order of evaluation. Java also uses a fairly intuitive operator precedence
rule to determine the order of evaluation when parentheses are not used. Unlike
C++, Java does not allow operator overloading for class types.
String Concatenation
With strings, the (+) operator performs concatenation, so that the code
String rug = "carpet";
String dog = "spot";
String mess = rug + dog;
String answer = mess + " will cost me " + 5 + " hours!";
would have the effect of making answer refer to the string
"carpetspot will cost me 5 hours!"
This example also shows how Java converts nonstring values (such as 5) into strings,
when they are involved in a string concatenation operation.
1.4. Expressions 25
Increment and Decrement Operators
Like C and C++, Java provides increment and decrement operators. Specifically, it
provides the plus-one increment (++) and decrement (−−) operators. If such an
operator is used in front of a variable reference, then 1 is added to (or subtracted
from) the variable and its value is read into the expression. If it is used after a
variable reference, then the value is first read and then the variable is incremented
or decremented by 1. So, for example, the code fragment
int i = 8;
int j = i++; // j becomes 8 and then i becomes 9
int k = ++i; // i becomes 10 and then k becomes 10
int m = i−−; // m becomes 10 and then i becomes 9
int n = 9 + −−i; // i becomes 8 and then n becomes 17
assigns 8 to j, 10 to k, 10 to m, 17 to n, and returns i to value 8, as noted.
Logical Operators
Java supports the standard comparisons operators between numbers:
< less than
<= less than or equal to
== equal to
!= not equal to
>= greater than or equal to
> greater than
The type of the result of any of these comparison is a boolean. Comparisons may
also be performed on char values, with inequalities determined according to the
underlying character codes.
For reference types, it is important to know that the operators == and != are
defined so that expression a == b is true if a and b both refer to the identical
object (or are both null). Most object types support an equals method, such that
a.equals(b) is true if a and b refer to what are deemed as “equivalent” instances for
that class (even if not the same instance); see Section 3.5 for further discussion.
Operators defined for boolean values are the following:
! not (prefix)
&& conditional and
|| conditional or
The boolean operators && and | | will not evaluate the second operand (to the right)
in their expression if it is not needed to determine the value of the expression. This
“short circuiting” feature is useful for constructing boolean expressions where we
first test that a certain condition holds (such as an array index being valid) and then
test a condition that could have otherwise generated an error condition had the prior
test not succeeded.
26 Chapter 1. Java Primer
Bitwise Operators
Java also provides the following bitwise operators for integers and booleans:
∼ bitwise complement (prefix unary operator)
& bitwise and
| bitwise or
ˆ bitwise exclusive-or
<< shift bits left, filling in with zeros
>> shift bits right, filling in with sign bit
>>> shift bits right, filling in with zeros
variable = expression
Operators in Java are given preferences, or precedence, that determine the order in
which operations are performed when the absence of parentheses brings up eval-
uation ambiguities. For example, we need a way of deciding if the expression,
“5+2*3,” has value 21 or 11 (Java says it is 11). We show the precedence of the
operators in Java (which, incidentally, is the same as in C and C++) in Table 1.3.
Operator Precedence
Type Symbols
1 array index []
method call ()
dot operator .
2 postfix ops exp++ exp−−
prefix ops ++exp −−exp +exp −exp ˜exp !exp
cast (type) exp
3 mult./div. ∗ / %
4 add./subt. + −
5 shift << >> >>>
6 comparison < <= > >= instanceof
7 equality == !=
8 bitwise-and &
9 bitwise-xor ˆ
10 bitwise-or |
11 and &&
12 or ||
13 conditional booleanExpression ? valueIfTrue : valueIfFalse
14 assignment = += −= ∗= /= %= <<= >>= >>>= &= ˆ= |=
Table 1.3: The Java precedence rules. Operators in Java are evaluated according to
the ordering above if parentheses are not used to determine the order of evaluation.
Operators on the same line are evaluated in left-to-right order (except for assign-
ment and prefix operations, which are evaluated in right-to-left order), subject to
the conditional evaluation rule for boolean && and | | operations. The operations
are listed from highest to lowest precedence (we use exp to denote an atomic or
parenthesized expression). Without parenthesization, higher precedence operators
are performed before lower precedence operators.
We have now discussed almost all of the operators listed in Table 1.3. A notable
exception is the conditional operator, which involves evaluating a boolean expres-
sion and then taking on the appropriate value depending on whether this boolean
expression is true or false. (We discuss the use of the instanceof operator in the
next chapter.)
Other documents randomly have
different content
130.
Guide, III., chap. li.
131.
See R. Shem-Tob’s Commentary on the Guide, loc. cit.
132.
Ibid.
133.
Maimonides himself describes the contemporary state of
culture among his people in several places. See, for instance,
the Treatise on Resurrection.
134.
Emunoth v’ Deoth, Preface.
135.
R. Jehudah Halevi, despite his profound knowledge of
contemporary philosophy, says categorically: “He who accepts
this [the Law] completely, without scrutiny or argument, is
better off than he who investigates and analyses” (Cuzri, II.,
xxvi. [Dr. Hirschfeld’s translation]).
136.
Guide, I., chap. lxxi.
137. As to the state of mind of the forced converts at that time see
what Maimonides says in the Treatise of the Sanctification of
the Name and the Iggereth Teman.
138.
See Section II. above. Note especially what Maimonides says
about prophecy in the Introduction to his Commentary on the
Mishnah (written at the time when he lived among the forced
converts). Some of this is quoted in Section II. He writes there
with such incisive force as to make it clear that he has left the
realm of pure speculation and theory, and has a practical
object connected with actual circumstances which had stirred
him deeply at the time.
139.
All this is clearly hinted in Maimonides’ Treatise of the
Sanctification of the Name.
140.
Guide, III., chap. xxvii.
141.
We find all the principles of his system in the Introduction to
his first book (the Commentary on the Mishnah), and again at
the end of his last book (Guide, III., chap. li.).
142.
See Introduction to Commentary on the Mishnah.
143.
“This is not the place to treat of this matter; but it is my
intention, wherever a matter of belief is mentioned, to explain
it briefly. For I love to teach nothing so much as one of the
principles of religion” (end of Berachoth).
144.
Especially important in this connection are the Introductions to
Zera’im, to chapter Chelek (where he brings in all the principles
of religion), and to Aboth (Eight Chapters).
145.
His Preface makes it clear that he regarded his book as a sort
of Mishnah in a new form; and it seems (though he does not
say it in so many words) that he intended to hint at this idea
by the title of the book—Mishneh Torah.
146.
There were many writers who suspected that Maimonides’ idea
was to do away altogether with the study of the Talmud. But
this suspicion could arise only from failure to understand
clearly the real purpose of the book. Even theories are
presented here in dogmatic form; but could it possibly be
imagined that Maimonides wanted to do away with the study
of philosophy by the long method of argument and proof—that
study which he regarded as the purpose of the human race?
The truth is that he had in view the social function of religion,
and for this reason he set forth both theories and practical
commands in brief and in a manner suited to the
comprehension of ordinary men. He left it to the chosen few to
study the principles of both the theoretical and the practical
law, and to obtain from the original sources a knowledge of the
reasons for both.
148.
After the publication of the Guide many people discovered that
its opinions were already contained in the innocent-looking
dicta of the Mishneh Torah, especially in its first part (The Book
of Science), and from that time onward they regarded that
book also as heretical, and waged war on it as well as on the
Guide.
149.
See the letter of R. Jehudah Alfachar to Kimchi: Collected
Responses of Maimonides (ed. Leipsic), Part III., p. 1, et seq.
150.
See Dr. Joel’s monograph, Spinoza’s Theologisch-Politischer
Traktat auf seine Quellen geprüft, Breslau, 1870.
151.
See Kerem Chemed, III., pp. 67-70.
152.
I may remark in passing that Luzzatto (ibid.) accuses
Maimonides of yet another disservice to Judaism. By making
opinions the essential element of perfection Maimonides,
according to him, abolished the difference between the
righteous man and the wicked. “The philosopher,” he says,
“may commit theft, murder, and adultery, and yet attain eternal
life: salvation does not depend on merit.” This charge was
already brought against Maimonides by his medieval
opponents, but it is quite mistaken. Maimonides insists, over
and over again, that until a man has moral perfection it is
impossible for him to reach intellectual perfection to the degree
necessary for the attainment of acquired intellect. See, for
instance, the passage from the introduction to Zera’im quoted
above (p. 174).
153.
Though the conception of “nationalism” in its current sense is
modern, the national sentiment itself has existed in our people
at all times; and its existence and value have been realised in
our literature in every period, from the Bible and the Talmud to
the literature of Chassidism, though it used to be called by
other names (“the love of Israel,” etc.). But the sentiment and
its expression do not appear to the same extent or in the same
form in all ages and in all individuals, and it is therefore
legitimate to ask what was the attitude of any particular age or
any particular thinker to the national sentiment. An interesting
book might be written on the history of the national sentiment
and consciousness in Israel, dealing with their different
manifestations in different ages, their growth and decline, and
their expression in the life of the nation and the thought of its
great men in each period.
154.
Guide, III., chap. xliii. Similarly in chap. xlviii.
155.
End of Mishneh Torah.
156.
See the Iggereth Teman and the Treatise of the Sanctification
of the Name.
158.
Introduction to chapter Chelek.
159.
See Albo, Ikkarim, Part I, chap. 1.
160.
See his Introduction to the Sepher Hammitzvoth.
161.
I remarked on this point years ago in “Past and Future.” [See
Selected Essays by Ahad Ha’am, p. 87.]
162.
Cf. supra, p. 10.
163.
See the Treatise on Resurrection.
164.
Luzzatto (ubi supra) seems to suspect that Maimonides’ whole
treatment of resurrection was insincere, and that he was
deliberately throwing dust in the reader’s eyes, in order to
conceal his heresy. But this suspicion is absurd: Maimonides
was a man who was not afraid openly to reject even the
immortality of the soul, and to recast all the fundamental
beliefs of Judaism. Any unbiassed reader of the treatise must
realise that Maimonides defends resurrection with perfect
sincerity, but that he is unable to find the real grounds of his
own conviction, because he looks for them in his reason and
not in his feelings.
165.
Commentary on the Mishnah, Aboth, chap. i. 17.
166.
See his letters to Joseph ben Gabar, to the community of
Lunel, and to R. Samuel Ibn Tibbon (Collected Responses of
Maimonides (Leipsic), Part II., pp. 16, 27, 44).
168.
Notes of this kind are found right through the book (see e.g.
pp. 498-503, 691-3, and many other places); and it is unfair of
some Jewish critics to have passed over this fact in silence,
and to have described the book as though it were throughout
simply an attack on Judaism.
169.
Introduction, pp. xvii. xviii. ci.
170.
[The story is that a heathen made this demand of Hillel, whose
reply was: “What is hateful to thyself do not unto thy
neighbour—that is the whole Torah, and the rest is
commentary: go thou and fulfil it.”]
171.
Das Judentum und seine Geschichte (2nd edition), p. 26.
172.
John Stuart Mill writes: “In justice to the great Hebrew
lawgiver, it should always be remembered that the precept to
love thy neighbour as thyself already existed in the
Pentateuch; and very surprising it is to find it there” (Three
Essays on Religion, 2nd edition, p. 98). Had Mill understood
the precept in its original sense, he would certainly not have
been surprised to find it in the Mosaic Law. But even so logical
a thinker could not free himself from the influences of his
education and his environment, and he did not see that a
meaning had been read into this verse which was opposed to
its literal sense.
173.
The Russian philosopher Vladimir Solovioff was the first, if I am
not mistaken, to attempt to find a moral basis for international
relations in the precept “Thou shalt love thy neighbour as
thyself,” taken in the sense mentioned above. This philosopher
was an untiring student of Judaism, for which he had an
appreciation unusual among Christians—a fact not without its
significance.
174.
Mr. Montefiore, indeed, does not admit this. In his opinion the
morality of Jewish family life is a fact not because of the laws,
but in spite of them. If you ask how such a thing is possible,
he replies somewhat as follows: It has already been remarked
that Judaism does not obey the laws of cause and effect, and
we sometimes see a certain tendency in Jewish life which
ought logically to have certain effects, but has in practice just
the opposite results (p. 335). Truly an easy and comfortable
“philosophy of history”!
175.
Even Matthew, who permits divorce on the ground of
unfaithfulness, makes this exception (as some Christian
commentators have pointed out) only because the sanctity of
the marriage is profaned by the sin, and the divine union is
annulled of itself. The point of view is essentially the same in
both versions.
176.
In England the question has become so acute that the
Government has appointed a Commission to find means of
making divorce easier. Men of knowledge and experience, in
evidence before the Commission, have expressed the opinion
that the restriction of the possibility of divorce has very evil
results.
177. In England the law to-day is still in the spirit of Matthew; the
wife’s unfaithfulness is sufficient ground of divorce for the
husband, but the reverse does not hold good.
178.
[Divine Presence. See p. 97.]
Transcriber’s Notes:
Footnotes have been collected at the end of the text, and are
linked for ease of reference.
*** END OF THE PROJECT GUTENBERG EBOOK TEN ESSAYS ON
ZIONISM AND JUDAISM ***
1.D. The copyright laws of the place where you are located also
govern what you can do with this work. Copyright laws in most
countries are in a constant state of change. If you are outside
the United States, check the laws of your country in addition to
the terms of this agreement before downloading, copying,
displaying, performing, distributing or creating derivative works
based on this work or any other Project Gutenberg™ work. The
Foundation makes no representations concerning the copyright
status of any work in any country other than the United States.
1.E.6. You may convert to and distribute this work in any binary,
compressed, marked up, nonproprietary or proprietary form,
including any word processing or hypertext form. However, if
you provide access to or distribute copies of a Project
Gutenberg™ work in a format other than “Plain Vanilla ASCII” or
other format used in the official version posted on the official
Project Gutenberg™ website (www.gutenberg.org), you must,
at no additional cost, fee or expense to the user, provide a copy,
a means of exporting a copy, or a means of obtaining a copy
upon request, of the work in its original “Plain Vanilla ASCII” or
other form. Any alternate format must include the full Project
Gutenberg™ License as specified in paragraph 1.E.1.
• You pay a royalty fee of 20% of the gross profits you derive
from the use of Project Gutenberg™ works calculated using the
method you already use to calculate your applicable taxes. The
fee is owed to the owner of the Project Gutenberg™ trademark,
but he has agreed to donate royalties under this paragraph to
the Project Gutenberg Literary Archive Foundation. Royalty
payments must be paid within 60 days following each date on
which you prepare (or are legally required to prepare) your
periodic tax returns. Royalty payments should be clearly marked
as such and sent to the Project Gutenberg Literary Archive
Foundation at the address specified in Section 4, “Information
about donations to the Project Gutenberg Literary Archive
Foundation.”
• You comply with all other terms of this agreement for free
distribution of Project Gutenberg™ works.
1.F.
Most people start at our website which has the main PG search
facility: www.gutenberg.org.
Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.
ebookultra.com