- •Preface
- •1.1 Machine Language
- •1.3 The Java Virtual Machine
- •1.4 Building Blocks of Programs
- •1.5 Object-oriented Programming
- •1.6 The Modern User Interface
- •Quiz on Chapter 1
- •2 Names and Things
- •2.1 The Basic Java Application
- •2.2.1 Variables
- •2.2.2 Types and Literals
- •2.2.3 Variables in Programs
- •2.3.2 Operations on Strings
- •2.3.3 Introduction to Enums
- •2.4 Text Input and Output
- •2.4.1 A First Text Input Example
- •2.4.2 Text Output
- •2.4.3 TextIO Input Functions
- •2.4.4 Formatted Output
- •2.4.5 Introduction to File I/O
- •2.5 Details of Expressions
- •2.5.1 Arithmetic Operators
- •2.5.2 Increment and Decrement
- •2.5.3 Relational Operators
- •2.5.4 Boolean Operators
- •2.5.5 Conditional Operator
- •2.5.7 Type Conversion of Strings
- •2.5.8 Precedence Rules
- •2.6 Programming Environments
- •2.6.1 Java Development Kit
- •2.6.2 Command Line Environment
- •2.6.3 IDEs and Eclipse
- •2.6.4 The Problem of Packages
- •Exercises for Chapter 2
- •Quiz on Chapter 2
- •3 Control
- •3.1 Blocks, Loops, and Branches
- •3.1.1 Blocks
- •3.1.2 The Basic While Loop
- •3.1.3 The Basic If Statement
- •3.2 Algorithm Development
- •3.2.2 The 3N+1 Problem
- •3.2.3 Coding, Testing, Debugging
- •3.3.1 The while Statement
- •3.3.2 The do..while Statement
- •3.3.3 break and continue
- •3.4 The for Statement
- •3.4.1 For Loops
- •3.4.2 Example: Counting Divisors
- •3.4.3 Nested for Loops
- •3.5 The if Statement
- •3.5.1 The Dangling else Problem
- •3.5.2 The if...else if Construction
- •3.5.3 If Statement Examples
- •3.5.4 The Empty Statement
- •3.6 The switch Statement
- •3.6.1 The Basic switch Statement
- •3.6.2 Menus and switch Statements
- •3.6.3 Enums in switch Statements
- •3.7.1 Exceptions
- •3.7.2 try..catch
- •3.7.3 Exceptions in TextIO
- •Exercises for Chapter 3
- •Quiz on Chapter 3
- •4 Subroutines
- •4.1 Black Boxes
- •4.2.2 Calling Subroutines
- •4.2.3 Subroutines in Programs
- •4.2.4 Member Variables
- •4.3 Parameters
- •4.3.1 Using Parameters
- •4.3.2 Formal and Actual Parameters
- •4.3.3 Overloading
- •4.3.4 Subroutine Examples
- •4.3.5 Throwing Exceptions
- •4.3.6 Global and Local Variables
- •4.4 Return Values
- •4.4.1 The return statement
- •4.4.2 Function Examples
- •4.4.3 3N+1 Revisited
- •4.5 APIs, Packages, and Javadoc
- •4.5.1 Toolboxes
- •4.5.3 Using Classes from Packages
- •4.5.4 Javadoc
- •4.6 More on Program Design
- •4.6.1 Preconditions and Postconditions
- •4.6.2 A Design Example
- •4.6.3 The Program
- •4.7 The Truth About Declarations
- •4.7.1 Initialization in Declarations
- •4.7.2 Named Constants
- •4.7.3 Naming and Scope Rules
- •Exercises for Chapter 4
- •Quiz on Chapter 4
- •5 Objects and Classes
- •5.1.1 Objects, Classes, and Instances
- •5.1.2 Fundamentals of Objects
- •5.1.3 Getters and Setters
- •5.2 Constructors and Object Initialization
- •5.2.1 Initializing Instance Variables
- •5.2.2 Constructors
- •5.2.3 Garbage Collection
- •5.3 Programming with Objects
- •5.3.2 Wrapper Classes and Autoboxing
- •5.4 Programming Example: Card, Hand, Deck
- •5.4.1 Designing the classes
- •5.4.2 The Card Class
- •5.4.3 Example: A Simple Card Game
- •5.5.1 Extending Existing Classes
- •5.5.2 Inheritance and Class Hierarchy
- •5.5.3 Example: Vehicles
- •5.5.4 Polymorphism
- •5.5.5 Abstract Classes
- •5.6 this and super
- •5.6.1 The Special Variable this
- •5.6.2 The Special Variable super
- •5.6.3 Constructors in Subclasses
- •5.7 Interfaces, Nested Classes, and Other Details
- •5.7.1 Interfaces
- •5.7.2 Nested Classes
- •5.7.3 Anonymous Inner Classes
- •5.7.5 Static Import
- •5.7.6 Enums as Classes
- •Exercises for Chapter 5
- •Quiz on Chapter 5
- •6 Introduction to GUI Programming
- •6.1 The Basic GUI Application
- •6.1.1 JFrame and JPanel
- •6.1.2 Components and Layout
- •6.1.3 Events and Listeners
- •6.2 Applets and HTML
- •6.2.1 JApplet
- •6.2.2 Reusing Your JPanels
- •6.2.3 Basic HTML
- •6.2.4 Applets on Web Pages
- •6.3 Graphics and Painting
- •6.3.1 Coordinates
- •6.3.2 Colors
- •6.3.3 Fonts
- •6.3.4 Shapes
- •6.3.5 Graphics2D
- •6.3.6 An Example
- •6.4 Mouse Events
- •6.4.1 Event Handling
- •6.4.2 MouseEvent and MouseListener
- •6.4.3 Mouse Coordinates
- •6.4.4 MouseMotionListeners and Dragging
- •6.4.5 Anonymous Event Handlers
- •6.5 Timer and Keyboard Events
- •6.5.1 Timers and Animation
- •6.5.2 Keyboard Events
- •6.5.3 Focus Events
- •6.5.4 State Machines
- •6.6 Basic Components
- •6.6.1 JButton
- •6.6.2 JLabel
- •6.6.3 JCheckBox
- •6.6.4 JTextField and JTextArea
- •6.6.5 JComboBox
- •6.6.6 JSlider
- •6.7 Basic Layout
- •6.7.1 Basic Layout Managers
- •6.7.2 Borders
- •6.7.3 SliderAndComboBoxDemo
- •6.7.4 A Simple Calculator
- •6.7.5 Using a null Layout
- •6.7.6 A Little Card Game
- •6.8 Menus and Dialogs
- •6.8.1 Menus and Menubars
- •6.8.2 Dialogs
- •6.8.3 Fine Points of Frames
- •6.8.4 Creating Jar Files
- •Exercises for Chapter 6
- •Quiz on Chapter 6
- •7 Arrays
- •7.1 Creating and Using Arrays
- •7.1.1 Arrays
- •7.1.2 Using Arrays
- •7.1.3 Array Initialization
- •7.2 Programming With Arrays
- •7.2.1 Arrays and for Loops
- •7.2.3 Array Types in Subroutines
- •7.2.4 Random Access
- •7.2.5 Arrays of Objects
- •7.2.6 Variable Arity Methods
- •7.3 Dynamic Arrays and ArrayLists
- •7.3.1 Partially Full Arrays
- •7.3.2 Dynamic Arrays
- •7.3.3 ArrrayLists
- •7.3.4 Parameterized Types
- •7.3.5 Vectors
- •7.4 Searching and Sorting
- •7.4.1 Searching
- •7.4.2 Association Lists
- •7.4.3 Insertion Sort
- •7.4.4 Selection Sort
- •7.4.5 Unsorting
- •7.5.3 Example: Checkers
- •Exercises for Chapter 7
- •Quiz on Chapter 7
- •8 Correctness and Robustness
- •8.1 Introduction to Correctness and Robustness
- •8.1.1 Horror Stories
- •8.1.2 Java to the Rescue
- •8.1.3 Problems Remain in Java
- •8.2 Writing Correct Programs
- •8.2.1 Provably Correct Programs
- •8.2.2 Robust Handling of Input
- •8.3 Exceptions and try..catch
- •8.3.1 Exceptions and Exception Classes
- •8.3.2 The try Statement
- •8.3.3 Throwing Exceptions
- •8.3.4 Mandatory Exception Handling
- •8.3.5 Programming with Exceptions
- •8.4 Assertions
- •8.5 Introduction to Threads
- •8.5.1 Creating and Running Threads
- •8.5.2 Operations on Threads
- •8.5.4 Wait and Notify
- •8.5.5 Volatile Variables
- •8.6 Analysis of Algorithms
- •Exercises for Chapter 8
- •Quiz on Chapter 8
- •9.1 Recursion
- •9.1.1 Recursive Binary Search
- •9.1.2 Towers of Hanoi
- •9.1.3 A Recursive Sorting Algorithm
- •9.1.4 Blob Counting
- •9.2 Linked Data Structures
- •9.2.1 Recursive Linking
- •9.2.2 Linked Lists
- •9.2.3 Basic Linked List Processing
- •9.2.4 Inserting into a Linked List
- •9.2.5 Deleting from a Linked List
- •9.3 Stacks, Queues, and ADTs
- •9.3.1 Stacks
- •9.3.2 Queues
- •9.4 Binary Trees
- •9.4.1 Tree Traversal
- •9.4.2 Binary Sort Trees
- •9.4.3 Expression Trees
- •9.5 A Simple Recursive Descent Parser
- •9.5.1 Backus-Naur Form
- •9.5.2 Recursive Descent Parsing
- •9.5.3 Building an Expression Tree
- •Exercises for Chapter 9
- •Quiz on Chapter 9
- •10.1 Generic Programming
- •10.1.1 Generic Programming in Smalltalk
- •10.1.2 Generic Programming in C++
- •10.1.3 Generic Programming in Java
- •10.1.4 The Java Collection Framework
- •10.1.6 Equality and Comparison
- •10.1.7 Generics and Wrapper Classes
- •10.2 Lists and Sets
- •10.2.1 ArrayList and LinkedList
- •10.2.2 Sorting
- •10.2.3 TreeSet and HashSet
- •10.2.4 EnumSet
- •10.3 Maps
- •10.3.1 The Map Interface
- •10.3.2 Views, SubSets, and SubMaps
- •10.3.3 Hash Tables and Hash Codes
- •10.4 Programming with the Collection Framework
- •10.4.1 Symbol Tables
- •10.4.2 Sets Inside a Map
- •10.4.3 Using a Comparator
- •10.4.4 Word Counting
- •10.5 Writing Generic Classes and Methods
- •10.5.1 Simple Generic Classes
- •10.5.2 Simple Generic Methods
- •10.5.3 Type Wildcards
- •10.5.4 Bounded Types
- •Exercises for Chapter 10
- •Quiz on Chapter 10
- •11 Files and Networking
- •11.1 Streams, Readers, and Writers
- •11.1.1 Character and Byte Streams
- •11.1.2 PrintWriter
- •11.1.3 Data Streams
- •11.1.4 Reading Text
- •11.1.5 The Scanner Class
- •11.1.6 Serialized Object I/O
- •11.2 Files
- •11.2.1 Reading and Writing Files
- •11.2.2 Files and Directories
- •11.2.3 File Dialog Boxes
- •11.3 Programming With Files
- •11.3.1 Copying a File
- •11.3.2 Persistent Data
- •11.3.3 Files in GUI Programs
- •11.3.4 Storing Objects in Files
- •11.4 Networking
- •11.4.1 URLs and URLConnections
- •11.4.2 TCP/IP and Client/Server
- •11.4.3 Sockets
- •11.4.4 A Trivial Client/Server
- •11.4.5 A Simple Network Chat
- •11.5 Network Programming and Threads
- •11.5.1 A Threaded GUI Chat Program.
- •11.5.2 A Multithreaded Server
- •11.5.3 Distributed Computing
- •11.6 A Brief Introduction to XML
- •11.6.1 Basic XML Syntax
- •11.6.2 XMLEncoder and XMLDecoder
- •11.6.3 Working With the DOM
- •Exercises for Chapter 11
- •Quiz on Chapter 11
- •12 Advanced GUI Programming
- •12.1 Images and Resources
- •12.1.2 Working With Pixels
- •12.1.3 Resources
- •12.1.4 Cursors and Icons
- •12.1.5 Image File I/O
- •12.2 Fancier Graphics
- •12.2.1 Measuring Text
- •12.2.2 Transparency
- •12.2.3 Antialiasing
- •12.2.4 Strokes and Paints
- •12.2.5 Transforms
- •12.3 Actions and Buttons
- •12.3.1 Action and AbstractAction
- •12.3.2 Icons on Buttons
- •12.3.3 Radio Buttons
- •12.3.4 Toolbars
- •12.3.5 Keyboard Accelerators
- •12.3.6 HTML on Buttons
- •12.4 Complex Components and MVC
- •12.4.1 Model-View-Controller
- •12.4.2 Lists and ListModels
- •12.4.3 Tables and TableModels
- •12.4.4 Documents and Editors
- •12.4.5 Custom Components
- •12.5 Finishing Touches
- •12.5.1 The Mandelbrot Set
- •12.5.2 Design of the Program
- •12.5.3 Internationalization
- •12.5.4 Events, Events, Events
- •12.5.5 Custom Dialogs
- •12.5.6 Preferences
- •Exercises for Chapter 12
- •Quiz on Chapter 12
- •Appendix: Source Files
CHAPTER 10. GENERIC PROGRAMMING AND COLLECTION CLASSES |
514 |
|
|
The only remaining problem is to print the data. We have to print the data from all the |
|
||
WordData objects twice, first in alphabetical order and then sorted according to frequency |
|
||
count. The data is in alphabetical order in the TreeMap, or more precisely, in the values of |
|
||
the TreeMap. We can use a for-each loop to print the data in the collection words.values(), |
|
||
and the words will appear in alphabetical order. Another for-each loop can be used to print |
|
||
the data in the list wordsByFrequency, and the words will be printed in order of decreasing |
|
||
frequency. Here is the code that does it: |
|
|
|
TextIO.putln("List of words in alphabetical order" |
|
|
|
+ " (with counts in parentheses):\n"); |
|
|
|
for ( WordData data : words.values() ) |
|
|
|
TextIO.putln(" |
" + data.word + " (" + data.count + ")"); |
|
|
TextIO.putln("\n\nList of words by frequency of occurrence:\n"); |
|
|
|
for ( WordData data : wordsByFrequency ) |
|
|
|
TextIO.putln(" |
" + data.word + " (" + data.count + ")"); |
|
|
You can find the complete word-counting program in the file WordCount.java. Note that for |
|
||
reading and writing files, it uses the file I/O capabilities of TextIO.java, which were discussed |
|
||
in Subsection 2.4.5. |
|
|
|
By the way, if you run the WordCount program on a reasonably large file and take a look |
|
||
at the output, it will illustrate something about the Collections.sort() method. The second |
|
||
list of words in the output is ordered by frequency, but if you look at a group of words that all |
|
||
have the same frequency, you will see that the words in that group are in alphabetical order. |
|
||
The method Collections.sort() was applied to sort the words by frequency, but before it was |
|
||
applied, the words were already in alphabetical order. When Collections.sort() rearranged |
|
||
the words, it did not change the ordering of words that have the same frequency, so they were |
|
||
still in alphabetical order within the group of words with that frequency. This is because the |
|
||
algorithm used by Collections.sort() is a stable sorting algorithm. A sorting algorithm is |
|
||
said to be stable if it satisfies the following condition: When the algorithm is used to sort a list |
|
||
according to some property of the items in the list, then the sort does not change the relative |
|
||
order of items that have the same value of that property. That is, if item B comes after item A |
|
||
in the list before the sort, and if both items have the same value for the property that is being |
|
||
used as the basis for sorting, then item B will still come after item A after the sorting has |
|
||
been done. Neither SelectionSort nor QuickSort are stable sorting algorithms. Insertion sort is |
|
||
stable, but is not very fast. The sorting algorithm used by Collections.sort() is both stable |
|
||
and fast. |
|
|
|
I hope that the programming examples in this section have convinced you of the usefulness |
|
||
of the Java Collection Framework! |
|
|
|
10.5 Writing Generic Classes and Methods |
|
|
|
So far in this chapter, you have learned about using the generic classes and methods that |
(online) |
||
are part of the Java Collection Framework. Now, it’s time to learn how to write new generic |
|
classes and methods from scratch. Generic programming produces highly general and reusable code—it’s very useful for people who write reusable software libraries to know how to do generic programming, since it enables them to write code that can be used in many di erent situations. Not every programmer needs to write reusable software libraries, but every programmer should know at least a little about how to do it. In fact, just to read the JavaDoc documentation for
CHAPTER 10. GENERIC PROGRAMMING AND COLLECTION CLASSES |
515 |
Java’s standard generic classes, you need to know some of the syntax that is introduced in this section.
I will not cover every detail of generic programming in Java in this section, but the material presented here should be su cient to cover the most common cases.
10.5.1Simple Generic Classes
Let’s start with an example that illustrates the motivation for generic programming. In Subsection 10.2.1, I remarked that it would be easy to use a LinkedList to implement a queue. (Queues were introduced in Subsection 9.3.2.) To ensure that the only operations that are performed on the list are the queue operations enqueue, dequeue, and isEmpty, we can create a new class that contains the linked list as a private instance variable. To implement queues of strings, for example, we can define the class:
class QueueOfStrings {
private LinkedList<String> items = new LinkedList<String>(); public void enqueue(String item) {
items.addLast(item);
}
public String dequeue() { return items.removeFirst();
}
public boolean isEmpty() { return (items.size() == 0);
}
}
This is a fine and useful class. But, if this is how we write queue classes, and if we want queues of Integers or Doubles or JButtons or any other type, then we will have to write a di erent class for each type. The code for all of these classes will be almost identical, which seems like a lot of redundant programming. To avoid the redundancy, we can write a generic Queue class that can be used to define queues of any type of object.
The syntax for writing the generic class is straightforward: We replace the specific type String with a type parameter such as T, and we add the type parameter to the name of the class:
class Queue<T> {
private LinkedList<T> items = new LinkedList<T>(); public void enqueue(T item) {
items.addLast(item);
}
public T dequeue() {
return items.removeFirst();
}
public boolean isEmpty() { return (items.size() == 0);
}
}
Note that within the class, the type parameter T is used just like any regular type name. It’s used to declare the return type for dequeue, as the type of the formal parameter item in enqueue, and even as the actual type parameter in LinkedList<T>. Given this class definition, we can use parameterized types such as Queue<String> and Queue<Integer> and Queue<JButton>.
CHAPTER 10. GENERIC PROGRAMMING AND COLLECTION CLASSES |
516 |
That is, the Queue class is used in exactly the same way as built-in generic classes like LinkedList and HashSet.
Note that you don’t have to use “T” as the name of the type parameter in the definition of the generic class. Type parameters are like formal parameters in subroutines. You can make up any name you like in the definition of the class. The name in the definition will be replaced by an actual type name when the class is used to declare variables or create objects. If you prefer to use a more meaningful name for the type parameter, you might define the Queue class as:
class Queue<ItemType> {
private LinkedList<ItemType> items = new LinkedList<ItemType>(); public void enqueue(ItemType item) {
items.addLast(item);
}
public ItemType dequeue() { return items.removeFirst();
}
public boolean isEmpty() { return (items.size() == 0);
}
}
Changing the name from “T” to “ItemType” has absolutely no e ect on the meaning of the class definition or on the way that Queue is used.
Generic interfaces can be defined in a similar way. It’s also easy to define generic classes and interfaces that have two or more type parameters, as is done with the standard interface Map<T,S>. A typical example is the definition of a “Pair” that contains two objects, possibly of di erent types. A simple version of such a class can be defined as:
class Pair<T,S> { public T first; public S second;
public Pair( T a, S b ) { // Constructor. first = a;
second = b;
}
}
This class can be used to declare variables and create objects such as:
Pair<String,Color> colorName = new Pair<String,Color>("Red", Color.RED); Pair<Double,Double> coordinates = new Pair<Double,Double>(17.3,42.8);
Note that in the definition of the constructor in this class, the name “Pair” does not have type parameters. You might have expected “Pair<T,S>. However, the name of the class is “Pair”, not “Pair<T,S>, and within the definition of the class, “T” and “S” are used as if they are the names of specific, actual types. Note in any case that type parameters are never added to the names of methods or constructors, only to the names of classes and interfaces.
10.5.2Simple Generic Methods
In addition to generic classes, Java also has generic methods. An example is the method Collections.sort(), which can sort collections of objects of any type. To see how to write generic methods, let’s start with a non-generic method for counting the number of times that a given string occurs in an array of strings:
CHAPTER 10. GENERIC PROGRAMMING AND COLLECTION CLASSES |
517 |
/**
*Returns the number of times that itemToCount occurs in list. Items in the
*list are tested for equality using itemToCount.equals(), except in the
*special case where itemToCount is null.
*/
public static int countOccurrences(String[] list, String itemToCount) { int count = 0;
if (itemToCount == null) {
for ( String listItem : list ) if (listItem == null)
count++;
}
else {
for ( String listItem : list )
if (itemToCount.equals(listItem)) count++;
}
return count;
}
Once again, we have some code that works for type String, and we can imagine writing almost identical code to work with other types of objects. By writing a generic method, we get to write a single method definition that will work for objects of any type. We need to replace the specific type String in the definition of the method with the name of a type parameter, such as T. However, if that’s the only change we make, the compiler will think that “T” is the name of an actual type, and it will mark it as an undeclared identifier. We need some way of telling the compiler that “T” is a type parameter. That’s what the “<T>” does in the definition of the generic class “class Queue<T> { ...”. For a generic method, the “<T>” goes just before the name of the return type of the method:
public static <T> int countOccurrences(T[] list, T itemToCount) { int count = 0;
if (itemToCount == null) { for ( T listItem : list )
if (listItem == null) count++;
}
else {
for ( T listItem : list )
if (itemToCount.equals(listItem)) count++;
}
return count;
}
The “<T>” marks the method as being generic and specifies the name of the type parameter that will be used in the definition. Of course, the name of the type parameter doesn’t have to be “T”; it can be anything. (The “<T>” looks a little strange in that position, I know, but it had to go somewhere and that’s just where the designers of Java decided to put it.)
Given the generic method definition, we can apply it to objects of any type. If wordList is a variable of type String[ ] and word is a variable of type String, then
int ct = countOccurrences( wordList, word );