diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1fcb152
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+out
diff --git a/README.md b/README.md
index c293dbf..36ebc34 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1 @@
-java
-====
+Core Java
diff --git a/java.iml b/java.iml
new file mode 100644
index 0000000..c90834f
--- /dev/null
+++ b/java.iml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/java.ipr b/java.ipr
new file mode 100644
index 0000000..9d2eee6
--- /dev/null
+++ b/java.ipr
@@ -0,0 +1,308 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+
+
+ -
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1.8
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pattern/pattern.iml b/pattern/pattern.iml
new file mode 100644
index 0000000..c90834f
--- /dev/null
+++ b/pattern/pattern.iml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/javapattern/behavioral/command/Client.java b/pattern/src/behavioral/command/Client.java
similarity index 87%
rename from src/javapattern/behavioral/command/Client.java
rename to pattern/src/behavioral/command/Client.java
index 1105b7d..20b4780 100644
--- a/src/javapattern/behavioral/command/Client.java
+++ b/pattern/src/behavioral/command/Client.java
@@ -1,4 +1,4 @@
-package javapattern.behavioral.command;
+package behavioral.command;
/**
* @author DongZhukai
diff --git a/src/javapattern/behavioral/command/Command.java b/pattern/src/behavioral/command/Command.java
similarity index 70%
rename from src/javapattern/behavioral/command/Command.java
rename to pattern/src/behavioral/command/Command.java
index 68037ad..64dc58f 100644
--- a/src/javapattern/behavioral/command/Command.java
+++ b/pattern/src/behavioral/command/Command.java
@@ -1,4 +1,4 @@
-package javapattern.behavioral.command;
+package behavioral.command;
/**
* @author DongZhukai
diff --git a/src/javapattern/behavioral/command/ConcreteCommand.java b/pattern/src/behavioral/command/ConcreteCommand.java
similarity index 87%
rename from src/javapattern/behavioral/command/ConcreteCommand.java
rename to pattern/src/behavioral/command/ConcreteCommand.java
index 0b2b04a..f970a58 100644
--- a/src/javapattern/behavioral/command/ConcreteCommand.java
+++ b/pattern/src/behavioral/command/ConcreteCommand.java
@@ -1,4 +1,4 @@
-package javapattern.behavioral.command;
+package behavioral.command;
/**
* @author DongZhukai
diff --git a/src/javapattern/behavioral/command/Invoker.java b/pattern/src/behavioral/command/Invoker.java
similarity index 84%
rename from src/javapattern/behavioral/command/Invoker.java
rename to pattern/src/behavioral/command/Invoker.java
index f47484c..0b2e9cd 100644
--- a/src/javapattern/behavioral/command/Invoker.java
+++ b/pattern/src/behavioral/command/Invoker.java
@@ -1,4 +1,4 @@
-package javapattern.behavioral.command;
+package behavioral.command;
/**
* @author DongZhukai
diff --git a/src/javapattern/behavioral/command/Receiver.java b/pattern/src/behavioral/command/Receiver.java
similarity index 76%
rename from src/javapattern/behavioral/command/Receiver.java
rename to pattern/src/behavioral/command/Receiver.java
index 0997168..901927e 100644
--- a/src/javapattern/behavioral/command/Receiver.java
+++ b/pattern/src/behavioral/command/Receiver.java
@@ -1,4 +1,4 @@
-package javapattern.behavioral.command;
+package behavioral.command;
/**
* @author DongZhukai
diff --git a/src/javapattern/behavioral/observer/ConcreteObserver.java b/pattern/src/behavioral/observer/ConcreteObserver.java
similarity index 81%
rename from src/javapattern/behavioral/observer/ConcreteObserver.java
rename to pattern/src/behavioral/observer/ConcreteObserver.java
index dbb5036..ab188ba 100644
--- a/src/javapattern/behavioral/observer/ConcreteObserver.java
+++ b/pattern/src/behavioral/observer/ConcreteObserver.java
@@ -1,4 +1,4 @@
-package javapattern.behavioral.observer;
+package behavioral.observer;
/**
* @author DongZhukai
diff --git a/src/javapattern/behavioral/observer/ConcreteSubject.java b/pattern/src/behavioral/observer/ConcreteSubject.java
similarity index 93%
rename from src/javapattern/behavioral/observer/ConcreteSubject.java
rename to pattern/src/behavioral/observer/ConcreteSubject.java
index cdc42df..43a7c76 100644
--- a/src/javapattern/behavioral/observer/ConcreteSubject.java
+++ b/pattern/src/behavioral/observer/ConcreteSubject.java
@@ -1,4 +1,4 @@
-package javapattern.behavioral.observer;
+package behavioral.observer;
import java.util.Iterator;
import java.util.Vector;
diff --git a/src/javapattern/behavioral/observer/Observer.java b/pattern/src/behavioral/observer/Observer.java
similarity index 78%
rename from src/javapattern/behavioral/observer/Observer.java
rename to pattern/src/behavioral/observer/Observer.java
index c5ed0d9..ea6bd68 100644
--- a/src/javapattern/behavioral/observer/Observer.java
+++ b/pattern/src/behavioral/observer/Observer.java
@@ -1,4 +1,4 @@
-package javapattern.behavioral.observer;
+package behavioral.observer;
/**
* @author DongZhukai
diff --git a/src/javapattern/behavioral/observer/Subject.java b/pattern/src/behavioral/observer/Subject.java
similarity index 86%
rename from src/javapattern/behavioral/observer/Subject.java
rename to pattern/src/behavioral/observer/Subject.java
index 17232c3..d6101fc 100644
--- a/src/javapattern/behavioral/observer/Subject.java
+++ b/pattern/src/behavioral/observer/Subject.java
@@ -1,4 +1,4 @@
-package javapattern.behavioral.observer;
+package behavioral.observer;
/**
* @author DongZhukai
diff --git a/src/javapattern/behavioral/observer/readme.txt b/pattern/src/behavioral/observer/readme.txt
similarity index 100%
rename from src/javapattern/behavioral/observer/readme.txt
rename to pattern/src/behavioral/observer/readme.txt
diff --git a/src/javapattern/behavioral/strategy/booksales/DiscountStrategy.java b/pattern/src/behavioral/strategy/booksales/DiscountStrategy.java
similarity index 88%
rename from src/javapattern/behavioral/strategy/booksales/DiscountStrategy.java
rename to pattern/src/behavioral/strategy/booksales/DiscountStrategy.java
index 11ac264..20564f9 100644
--- a/src/javapattern/behavioral/strategy/booksales/DiscountStrategy.java
+++ b/pattern/src/behavioral/strategy/booksales/DiscountStrategy.java
@@ -1,4 +1,4 @@
-package javapattern.behavioral.strategy.booksales;
+package behavioral.strategy.booksales;
/**
* @author DongZhukai
diff --git a/src/javapattern/behavioral/strategy/booksales/FlatRateStrategy.java b/pattern/src/behavioral/strategy/booksales/FlatRateStrategy.java
similarity index 89%
rename from src/javapattern/behavioral/strategy/booksales/FlatRateStrategy.java
rename to pattern/src/behavioral/strategy/booksales/FlatRateStrategy.java
index 97ed58a..62e7a4a 100644
--- a/src/javapattern/behavioral/strategy/booksales/FlatRateStrategy.java
+++ b/pattern/src/behavioral/strategy/booksales/FlatRateStrategy.java
@@ -1,4 +1,4 @@
-package javapattern.behavioral.strategy.booksales;
+package behavioral.strategy.booksales;
/**
* @author DongZhukai
diff --git a/src/javapattern/behavioral/strategy/booksales/NoDiscountStrategy.java b/pattern/src/behavioral/strategy/booksales/NoDiscountStrategy.java
similarity index 84%
rename from src/javapattern/behavioral/strategy/booksales/NoDiscountStrategy.java
rename to pattern/src/behavioral/strategy/booksales/NoDiscountStrategy.java
index 75a020c..6c891e3 100644
--- a/src/javapattern/behavioral/strategy/booksales/NoDiscountStrategy.java
+++ b/pattern/src/behavioral/strategy/booksales/NoDiscountStrategy.java
@@ -1,4 +1,4 @@
-package javapattern.behavioral.strategy.booksales;
+package behavioral.strategy.booksales;
/**
* @author DongZhukai
diff --git a/src/javapattern/behavioral/strategy/booksales/PercentageStrategy.java b/pattern/src/behavioral/strategy/booksales/PercentageStrategy.java
similarity index 89%
rename from src/javapattern/behavioral/strategy/booksales/PercentageStrategy.java
rename to pattern/src/behavioral/strategy/booksales/PercentageStrategy.java
index 952e6d6..78a716c 100644
--- a/src/javapattern/behavioral/strategy/booksales/PercentageStrategy.java
+++ b/pattern/src/behavioral/strategy/booksales/PercentageStrategy.java
@@ -1,4 +1,4 @@
-package javapattern.behavioral.strategy.booksales;
+package behavioral.strategy.booksales;
/**
* @author DongZhukai
diff --git a/src/javapattern/behavioral/strategy/readme.txt b/pattern/src/behavioral/strategy/readme.txt
similarity index 100%
rename from src/javapattern/behavioral/strategy/readme.txt
rename to pattern/src/behavioral/strategy/readme.txt
diff --git a/src/javapattern/behavioral/template/AbstractClass.java b/pattern/src/behavioral/template/AbstractClass.java
similarity index 88%
rename from src/javapattern/behavioral/template/AbstractClass.java
rename to pattern/src/behavioral/template/AbstractClass.java
index 83b90aa..40b7ead 100644
--- a/src/javapattern/behavioral/template/AbstractClass.java
+++ b/pattern/src/behavioral/template/AbstractClass.java
@@ -1,4 +1,4 @@
-package javapattern.behavioral.template;
+package behavioral.template;
/**
* @author DongZhukai
diff --git a/src/javapattern/behavioral/template/ConcreteClass.java b/pattern/src/behavioral/template/ConcreteClass.java
similarity index 87%
rename from src/javapattern/behavioral/template/ConcreteClass.java
rename to pattern/src/behavioral/template/ConcreteClass.java
index f79fd91..9bb382d 100644
--- a/src/javapattern/behavioral/template/ConcreteClass.java
+++ b/pattern/src/behavioral/template/ConcreteClass.java
@@ -1,4 +1,4 @@
-package javapattern.behavioral.template;
+package behavioral.template;
/**
diff --git a/src/javapattern/behavioral/template/readme.txt b/pattern/src/behavioral/template/readme.txt
similarity index 100%
rename from src/javapattern/behavioral/template/readme.txt
rename to pattern/src/behavioral/template/readme.txt
diff --git a/src/javapattern/creational/builder/Builder.java b/pattern/src/creational/builder/Builder.java
similarity index 83%
rename from src/javapattern/creational/builder/Builder.java
rename to pattern/src/creational/builder/Builder.java
index bfc5938..2355f90 100644
--- a/src/javapattern/creational/builder/Builder.java
+++ b/pattern/src/creational/builder/Builder.java
@@ -1,4 +1,4 @@
-package javapattern.creational.builder;
+package creational.builder;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/builder/ConcreteBuilder.java b/pattern/src/creational/builder/ConcreteBuilder.java
similarity index 88%
rename from src/javapattern/creational/builder/ConcreteBuilder.java
rename to pattern/src/creational/builder/ConcreteBuilder.java
index 43f4a65..877f399 100644
--- a/src/javapattern/creational/builder/ConcreteBuilder.java
+++ b/pattern/src/creational/builder/ConcreteBuilder.java
@@ -1,4 +1,4 @@
-package javapattern.creational.builder;
+package creational.builder;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/builder/Director.java b/pattern/src/creational/builder/Director.java
similarity index 86%
rename from src/javapattern/creational/builder/Director.java
rename to pattern/src/creational/builder/Director.java
index 8ebc53b..a15d216 100644
--- a/src/javapattern/creational/builder/Director.java
+++ b/pattern/src/creational/builder/Director.java
@@ -1,4 +1,4 @@
-package javapattern.creational.builder;
+package creational.builder;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/builder/Product.java b/pattern/src/creational/builder/Product.java
similarity index 64%
rename from src/javapattern/creational/builder/Product.java
rename to pattern/src/creational/builder/Product.java
index 9dec8b8..01896e8 100644
--- a/src/javapattern/creational/builder/Product.java
+++ b/pattern/src/creational/builder/Product.java
@@ -1,4 +1,4 @@
-package javapattern.creational.builder;
+package creational.builder;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/factory/abstractfactory/ConcreteCreator1.java b/pattern/src/creational/factory/abstractfactory/ConcreteCreator1.java
similarity index 81%
rename from src/javapattern/creational/factory/abstractfactory/ConcreteCreator1.java
rename to pattern/src/creational/factory/abstractfactory/ConcreteCreator1.java
index 0a9d014..34e7836 100644
--- a/src/javapattern/creational/factory/abstractfactory/ConcreteCreator1.java
+++ b/pattern/src/creational/factory/abstractfactory/ConcreteCreator1.java
@@ -1,4 +1,4 @@
-package javapattern.creational.factory.abstractfactory;
+package creational.factory.abstractfactory;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/factory/abstractfactory/ConcreteCreator2.java b/pattern/src/creational/factory/abstractfactory/ConcreteCreator2.java
similarity index 81%
rename from src/javapattern/creational/factory/abstractfactory/ConcreteCreator2.java
rename to pattern/src/creational/factory/abstractfactory/ConcreteCreator2.java
index d945c24..2a9e4ec 100644
--- a/src/javapattern/creational/factory/abstractfactory/ConcreteCreator2.java
+++ b/pattern/src/creational/factory/abstractfactory/ConcreteCreator2.java
@@ -1,4 +1,4 @@
-package javapattern.creational.factory.abstractfactory;
+package creational.factory.abstractfactory;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/factory/abstractfactory/Creator.java b/pattern/src/creational/factory/abstractfactory/Creator.java
similarity index 71%
rename from src/javapattern/creational/factory/abstractfactory/Creator.java
rename to pattern/src/creational/factory/abstractfactory/Creator.java
index a23a999..34d7835 100644
--- a/src/javapattern/creational/factory/abstractfactory/Creator.java
+++ b/pattern/src/creational/factory/abstractfactory/Creator.java
@@ -1,4 +1,4 @@
-package javapattern.creational.factory.abstractfactory;
+package creational.factory.abstractfactory;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/factory/abstractfactory/ProductA.java b/pattern/src/creational/factory/abstractfactory/ProductA.java
similarity index 58%
rename from src/javapattern/creational/factory/abstractfactory/ProductA.java
rename to pattern/src/creational/factory/abstractfactory/ProductA.java
index b883570..46f7b13 100644
--- a/src/javapattern/creational/factory/abstractfactory/ProductA.java
+++ b/pattern/src/creational/factory/abstractfactory/ProductA.java
@@ -1,4 +1,4 @@
-package javapattern.creational.factory.abstractfactory;
+package creational.factory.abstractfactory;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/factory/abstractfactory/ProductA1.java b/pattern/src/creational/factory/abstractfactory/ProductA1.java
similarity index 63%
rename from src/javapattern/creational/factory/abstractfactory/ProductA1.java
rename to pattern/src/creational/factory/abstractfactory/ProductA1.java
index ba7d13b..0ad75bf 100644
--- a/src/javapattern/creational/factory/abstractfactory/ProductA1.java
+++ b/pattern/src/creational/factory/abstractfactory/ProductA1.java
@@ -1,4 +1,4 @@
-package javapattern.creational.factory.abstractfactory;
+package creational.factory.abstractfactory;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/factory/abstractfactory/ProductA2.java b/pattern/src/creational/factory/abstractfactory/ProductA2.java
similarity index 63%
rename from src/javapattern/creational/factory/abstractfactory/ProductA2.java
rename to pattern/src/creational/factory/abstractfactory/ProductA2.java
index 150a250..12fcda1 100644
--- a/src/javapattern/creational/factory/abstractfactory/ProductA2.java
+++ b/pattern/src/creational/factory/abstractfactory/ProductA2.java
@@ -1,4 +1,4 @@
-package javapattern.creational.factory.abstractfactory;
+package creational.factory.abstractfactory;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/factory/abstractfactory/ProductB.java b/pattern/src/creational/factory/abstractfactory/ProductB.java
similarity index 58%
rename from src/javapattern/creational/factory/abstractfactory/ProductB.java
rename to pattern/src/creational/factory/abstractfactory/ProductB.java
index 255e961..68417a5 100644
--- a/src/javapattern/creational/factory/abstractfactory/ProductB.java
+++ b/pattern/src/creational/factory/abstractfactory/ProductB.java
@@ -1,4 +1,4 @@
-package javapattern.creational.factory.abstractfactory;
+package creational.factory.abstractfactory;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/factory/abstractfactory/ProductB1.java b/pattern/src/creational/factory/abstractfactory/ProductB1.java
similarity index 63%
rename from src/javapattern/creational/factory/abstractfactory/ProductB1.java
rename to pattern/src/creational/factory/abstractfactory/ProductB1.java
index 7fb803c..661a9da 100644
--- a/src/javapattern/creational/factory/abstractfactory/ProductB1.java
+++ b/pattern/src/creational/factory/abstractfactory/ProductB1.java
@@ -1,4 +1,4 @@
-package javapattern.creational.factory.abstractfactory;
+package creational.factory.abstractfactory;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/factory/abstractfactory/ProductB2.java b/pattern/src/creational/factory/abstractfactory/ProductB2.java
similarity index 63%
rename from src/javapattern/creational/factory/abstractfactory/ProductB2.java
rename to pattern/src/creational/factory/abstractfactory/ProductB2.java
index bcbd35a..c7734b7 100644
--- a/src/javapattern/creational/factory/abstractfactory/ProductB2.java
+++ b/pattern/src/creational/factory/abstractfactory/ProductB2.java
@@ -1,4 +1,4 @@
-package javapattern.creational.factory.abstractfactory;
+package creational.factory.abstractfactory;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/factory/factorymethod/Client.java b/pattern/src/creational/factory/factorymethod/Client.java
similarity index 86%
rename from src/javapattern/creational/factory/factorymethod/Client.java
rename to pattern/src/creational/factory/factorymethod/Client.java
index a0828d1..ca3d81a 100644
--- a/src/javapattern/creational/factory/factorymethod/Client.java
+++ b/pattern/src/creational/factory/factorymethod/Client.java
@@ -1,4 +1,4 @@
-package javapattern.creational.factory.factorymethod;
+package creational.factory.factorymethod;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/factory/factorymethod/ConcreteCreator1.java b/pattern/src/creational/factory/factorymethod/ConcreteCreator1.java
similarity index 77%
rename from src/javapattern/creational/factory/factorymethod/ConcreteCreator1.java
rename to pattern/src/creational/factory/factorymethod/ConcreteCreator1.java
index b6c63bc..2386fa4 100644
--- a/src/javapattern/creational/factory/factorymethod/ConcreteCreator1.java
+++ b/pattern/src/creational/factory/factorymethod/ConcreteCreator1.java
@@ -1,4 +1,4 @@
-package javapattern.creational.factory.factorymethod;
+package creational.factory.factorymethod;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/factory/factorymethod/ConcreteCreator2.java b/pattern/src/creational/factory/factorymethod/ConcreteCreator2.java
similarity index 77%
rename from src/javapattern/creational/factory/factorymethod/ConcreteCreator2.java
rename to pattern/src/creational/factory/factorymethod/ConcreteCreator2.java
index c13945c..b144f27 100644
--- a/src/javapattern/creational/factory/factorymethod/ConcreteCreator2.java
+++ b/pattern/src/creational/factory/factorymethod/ConcreteCreator2.java
@@ -1,4 +1,4 @@
-package javapattern.creational.factory.factorymethod;
+package creational.factory.factorymethod;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/factory/factorymethod/ConcreteProduct1.java b/pattern/src/creational/factory/factorymethod/ConcreteProduct1.java
similarity index 65%
rename from src/javapattern/creational/factory/factorymethod/ConcreteProduct1.java
rename to pattern/src/creational/factory/factorymethod/ConcreteProduct1.java
index 5883ce7..0d131f7 100644
--- a/src/javapattern/creational/factory/factorymethod/ConcreteProduct1.java
+++ b/pattern/src/creational/factory/factorymethod/ConcreteProduct1.java
@@ -1,4 +1,4 @@
-package javapattern.creational.factory.factorymethod;
+package creational.factory.factorymethod;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/factory/factorymethod/ConcreteProduct2.java b/pattern/src/creational/factory/factorymethod/ConcreteProduct2.java
similarity index 65%
rename from src/javapattern/creational/factory/factorymethod/ConcreteProduct2.java
rename to pattern/src/creational/factory/factorymethod/ConcreteProduct2.java
index c669cf8..ed18877 100644
--- a/src/javapattern/creational/factory/factorymethod/ConcreteProduct2.java
+++ b/pattern/src/creational/factory/factorymethod/ConcreteProduct2.java
@@ -1,4 +1,4 @@
-package javapattern.creational.factory.factorymethod;
+package creational.factory.factorymethod;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/factory/factorymethod/Creator.java b/pattern/src/creational/factory/factorymethod/Creator.java
similarity index 66%
rename from src/javapattern/creational/factory/factorymethod/Creator.java
rename to pattern/src/creational/factory/factorymethod/Creator.java
index 3d10295..9de8c94 100644
--- a/src/javapattern/creational/factory/factorymethod/Creator.java
+++ b/pattern/src/creational/factory/factorymethod/Creator.java
@@ -1,4 +1,4 @@
-package javapattern.creational.factory.factorymethod;
+package creational.factory.factorymethod;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/factory/factorymethod/Product.java b/pattern/src/creational/factory/factorymethod/Product.java
similarity index 59%
rename from src/javapattern/creational/factory/factorymethod/Product.java
rename to pattern/src/creational/factory/factorymethod/Product.java
index 4d13e07..4e29802 100644
--- a/src/javapattern/creational/factory/factorymethod/Product.java
+++ b/pattern/src/creational/factory/factorymethod/Product.java
@@ -1,4 +1,4 @@
-package javapattern.creational.factory.factorymethod;
+package creational.factory.factorymethod;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/factory/readme.txt b/pattern/src/creational/factory/readme.txt
similarity index 100%
rename from src/javapattern/creational/factory/readme.txt
rename to pattern/src/creational/factory/readme.txt
diff --git a/src/javapattern/creational/prototype/Client.java b/pattern/src/creational/prototype/Client.java
similarity index 82%
rename from src/javapattern/creational/prototype/Client.java
rename to pattern/src/creational/prototype/Client.java
index 9f9f3cc..e19626b 100644
--- a/src/javapattern/creational/prototype/Client.java
+++ b/pattern/src/creational/prototype/Client.java
@@ -1,4 +1,4 @@
-package javapattern.creational.prototype;
+package creational.prototype;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/prototype/Client2.java b/pattern/src/creational/prototype/Client2.java
similarity index 87%
rename from src/javapattern/creational/prototype/Client2.java
rename to pattern/src/creational/prototype/Client2.java
index 3d00f24..6279ea1 100644
--- a/src/javapattern/creational/prototype/Client2.java
+++ b/pattern/src/creational/prototype/Client2.java
@@ -1,4 +1,4 @@
-package javapattern.creational.prototype;
+package creational.prototype;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/prototype/ConcretePrototype.java b/pattern/src/creational/prototype/ConcretePrototype.java
similarity index 87%
rename from src/javapattern/creational/prototype/ConcretePrototype.java
rename to pattern/src/creational/prototype/ConcretePrototype.java
index 5ed5154..5a486ce 100644
--- a/src/javapattern/creational/prototype/ConcretePrototype.java
+++ b/pattern/src/creational/prototype/ConcretePrototype.java
@@ -1,4 +1,4 @@
-package javapattern.creational.prototype;
+package creational.prototype;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/prototype/Prototype.java b/pattern/src/creational/prototype/Prototype.java
similarity index 73%
rename from src/javapattern/creational/prototype/Prototype.java
rename to pattern/src/creational/prototype/Prototype.java
index 4e64f7d..a54271d 100644
--- a/src/javapattern/creational/prototype/Prototype.java
+++ b/pattern/src/creational/prototype/Prototype.java
@@ -1,4 +1,4 @@
-package javapattern.creational.prototype;
+package creational.prototype;
/**
* @author DongZhukai
diff --git a/src/javapattern/creational/prototype/PrototypeManager.java b/pattern/src/creational/prototype/PrototypeManager.java
similarity index 86%
rename from src/javapattern/creational/prototype/PrototypeManager.java
rename to pattern/src/creational/prototype/PrototypeManager.java
index d3cf67d..a744c54 100644
--- a/src/javapattern/creational/prototype/PrototypeManager.java
+++ b/pattern/src/creational/prototype/PrototypeManager.java
@@ -1,4 +1,4 @@
-package javapattern.creational.prototype;
+package creational.prototype;
import java.util.Vector;
diff --git a/volume1/v1ch06/AnonymousInnerClassTest/AnonymousInnerClassTest.iml b/volume1/v1ch06/AnonymousInnerClassTest/AnonymousInnerClassTest.iml
new file mode 100644
index 0000000..c90834f
--- /dev/null
+++ b/volume1/v1ch06/AnonymousInnerClassTest/AnonymousInnerClassTest.iml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/volume1/v1ch06/AnonymousInnerClassTest/src/AnonymousInnerClassTest.java b/volume1/v1ch06/AnonymousInnerClassTest/src/AnonymousInnerClassTest.java
new file mode 100755
index 0000000..8ea92a7
--- /dev/null
+++ b/volume1/v1ch06/AnonymousInnerClassTest/src/AnonymousInnerClassTest.java
@@ -0,0 +1,49 @@
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.Timer;
+
+/**
+ * This program demonstrates anonymous inner classes.
+ * @version 1.10 2004-02-27
+ * @author Cay Horstmann
+ */
+public class AnonymousInnerClassTest
+{
+ public static void main(String[] args)
+ {
+ TalkingClock clock = new TalkingClock();
+ clock.start(1000, true);
+
+ // keep program running until user selects "Ok"
+ JOptionPane.showMessageDialog(null, "Quit program?");
+ System.exit(0);
+ }
+}
+
+/**
+ * A clock that prints the time in regular intervals.
+ */
+class TalkingClock
+{
+ /**
+ * Starts the clock.
+ * @param interval the interval between messages (in milliseconds)
+ * @param beep true if the clock should beep
+ */
+ public void start(int interval, final boolean beep)
+ {
+ ActionListener listener = new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ Date now = new Date();
+ System.out.println("At the tone, the time is " + now);
+ if (beep) Toolkit.getDefaultToolkit().beep();
+ }
+ };
+ Timer t = new Timer(interval, listener);
+ t.start();
+ }
+}
diff --git a/volume1/v1ch06/CloneTest/CloneTest.java b/volume1/v1ch06/CloneTest/CloneTest.java
new file mode 100755
index 0000000..e5b0472
--- /dev/null
+++ b/volume1/v1ch06/CloneTest/CloneTest.java
@@ -0,0 +1,79 @@
+package CloneTest;
+
+import java.util.*;
+
+/**
+ * This program demonstrates cloning.
+ * @version 1.10 2002-07-01
+ * @author Cay Horstmann
+ */
+public class CloneTest
+{
+ public static void main(String[] args)
+ {
+ try
+ {
+ Employee original = new Employee("John Q. Public", 50000);
+ original.setHireDay(2000, 1, 1);
+ Employee copy = original.clone();
+ copy.raiseSalary(10);
+ copy.setHireDay(2002, 12, 31);
+ System.out.println("original=" + original);
+ System.out.println("copy=" + copy);
+ }
+ catch (CloneNotSupportedException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
+
+class Employee implements Cloneable
+{
+ public Employee(String n, double s)
+ {
+ name = n;
+ salary = s;
+ hireDay = new Date();
+ }
+
+ public Employee clone() throws CloneNotSupportedException
+ {
+ // call Object.clone()
+ Employee cloned = (Employee) super.clone();
+
+ // clone mutable fields
+ cloned.hireDay = (Date) hireDay.clone();
+
+ return cloned;
+ }
+
+ /**
+ * Set the hire day to a given date.
+ * @param year the year of the hire day
+ * @param month the month of the hire day
+ * @param day the day of the hire day
+ */
+ public void setHireDay(int year, int month, int day)
+ {
+ Date newHireDay = new GregorianCalendar(year, month - 1, day).getTime();
+
+ // Example of instance field mutation
+ hireDay.setTime(newHireDay.getTime());
+ }
+
+ public void raiseSalary(double byPercent)
+ {
+ double raise = salary * byPercent / 100;
+ salary += raise;
+ }
+
+ public String toString()
+ {
+ return "Employee[name=" + name + ",salary=" + salary + ",hireDay=" + hireDay + "]";
+ }
+
+ private String name;
+ private double salary;
+ private Date hireDay;
+}
diff --git a/volume1/v1ch06/EmployeeSortTest/EmployeeSortTest.java b/volume1/v1ch06/EmployeeSortTest/EmployeeSortTest.java
new file mode 100755
index 0000000..045bbcb
--- /dev/null
+++ b/volume1/v1ch06/EmployeeSortTest/EmployeeSortTest.java
@@ -0,0 +1,67 @@
+package EmployeeSortTest;
+
+import java.util.*;
+
+/**
+ * This program demonstrates the use of the Comparable interface.
+ * @version 1.30 2004-02-27
+ * @author Cay Horstmann
+ */
+public class EmployeeSortTest
+{
+ public static void main(String[] args)
+ {
+ Employee[] staff = new Employee[3];
+
+ staff[0] = new Employee("Harry Hacker", 35000);
+ staff[1] = new Employee("Carl Cracker", 75000);
+ staff[2] = new Employee("Tony Tester", 38000);
+
+ Arrays.sort(staff);
+
+ // print out information about all Employee objects
+ for (Employee e : staff)
+ System.out.println("name=" + e.getName() + ",salary=" + e.getSalary());
+ }
+}
+
+class Employee implements Comparable
+{
+ public Employee(String n, double s)
+ {
+ name = n;
+ salary = s;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public double getSalary()
+ {
+ return salary;
+ }
+
+ public void raiseSalary(double byPercent)
+ {
+ double raise = salary * byPercent / 100;
+ salary += raise;
+ }
+
+ /**
+ * Compares employees by salary
+ * @param other another Employee object
+ * @return a negative value if this employee has a lower salary than
+ * otherObject, 0 if the salaries are the same, a positive value otherwise
+ */
+ public int compareTo(Employee other)
+ {
+ if (salary < other.salary) return -1;
+ if (salary > other.salary) return 1;
+ return 0;
+ }
+
+ private String name;
+ private double salary;
+}
diff --git a/volume1/v1ch06/InnerClassTest/InnerClassTest.java b/volume1/v1ch06/InnerClassTest/InnerClassTest.java
new file mode 100755
index 0000000..9995736
--- /dev/null
+++ b/volume1/v1ch06/InnerClassTest/InnerClassTest.java
@@ -0,0 +1,65 @@
+package InnerClassTest;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.Timer;
+
+/**
+ * This program demonstrates the use of inner classes.
+ * @version 1.10 2004-02-27
+ * @author Cay Horstmann
+ */
+public class InnerClassTest
+{
+ public static void main(String[] args)
+ {
+ TalkingClock clock = new TalkingClock(1000, true);
+ clock.start();
+
+ // keep program running until user selects "Ok"
+ JOptionPane.showMessageDialog(null, "Quit program?");
+ System.exit(0);
+ }
+}
+
+/**
+ * A clock that prints the time in regular intervals.
+ */
+class TalkingClock
+{
+ /**
+ * Constructs a talking clock
+ * @param interval the interval between messages (in milliseconds)
+ * @param beep true if the clock should beep
+ */
+ public TalkingClock(int interval, boolean beep)
+ {
+ this.interval = interval;
+ this.beep = beep;
+ }
+
+ /**
+ * Starts the clock.
+ */
+ public void start()
+ {
+ ActionListener listener = new TimePrinter();
+ Timer t = new Timer(interval, listener);
+ t.start();
+ }
+
+ private int interval;
+ private boolean beep;
+
+ public class TimePrinter implements ActionListener
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ Date now = new Date();
+ System.out.println("At the tone, the time is " + now);
+ if (beep) Toolkit.getDefaultToolkit().beep();
+ }
+ }
+}
diff --git a/volume1/v1ch06/LocalInnerClassTest/LocalInnerClassTest.java b/volume1/v1ch06/LocalInnerClassTest/LocalInnerClassTest.java
new file mode 100755
index 0000000..3341cb4
--- /dev/null
+++ b/volume1/v1ch06/LocalInnerClassTest/LocalInnerClassTest.java
@@ -0,0 +1,52 @@
+package LocalInnerClassTest;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.Timer;
+
+/**
+ * This program demonstrates the use of local inner classes.
+ * @version 1.00 2004-02-27
+ * @author Cay Horstmann
+ */
+public class LocalInnerClassTest
+{
+ public static void main(String[] args)
+ {
+ TalkingClock clock = new TalkingClock();
+ clock.start(1000, true);
+
+ // keep program running until user selects "Ok"
+ JOptionPane.showMessageDialog(null, "Quit program?");
+ System.exit(0);
+ }
+}
+
+/**
+ * A clock that prints the time in regular intervals.
+ */
+class TalkingClock
+{
+ /**
+ * Starts the clock.
+ * @param interval the interval between messages (in milliseconds)
+ * @param beep true if the clock should beep
+ */
+ public void start(int interval, final boolean beep)
+ {
+ class TimePrinter implements ActionListener
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ Date now = new Date();
+ System.out.println("At the tone, the time is " + now);
+ if (beep) Toolkit.getDefaultToolkit().beep();
+ }
+ }
+ ActionListener listener = new TimePrinter();
+ Timer t = new Timer(interval, listener);
+ t.start();
+ }
+}
diff --git a/volume1/v1ch06/ProxyTest/ProxyTest.java b/volume1/v1ch06/ProxyTest/ProxyTest.java
new file mode 100755
index 0000000..37a1163
--- /dev/null
+++ b/volume1/v1ch06/ProxyTest/ProxyTest.java
@@ -0,0 +1,74 @@
+package ProxyTest;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+/**
+ * This program demonstrates the use of proxies.
+ * @version 1.00 2000-04-13
+ * @author Cay Horstmann
+ */
+public class ProxyTest
+{
+ public static void main(String[] args)
+ {
+ Object[] elements = new Object[1000];
+
+ // fill elements with proxies for the integers 1 ... 1000
+ for (int i = 0; i < elements.length; i++)
+ {
+ Integer value = i + 1;
+ InvocationHandler handler = new TraceHandler(value);
+ Object proxy = Proxy.newProxyInstance(null, new Class[] { Comparable.class } , handler);
+ elements[i] = proxy;
+ }
+
+ // construct a random integer
+ Integer key = new Random().nextInt(elements.length) + 1;
+
+ // search for the key
+ int result = Arrays.binarySearch(elements, key);
+
+ // print match if found
+ if (result >= 0) System.out.println(elements[result]);
+ }
+}
+
+/**
+ * An invocation handler that prints out the method name and parameters, then
+ * invokes the original method
+ */
+class TraceHandler implements InvocationHandler
+{
+ /**
+ * Constructs a TraceHandler
+ * @param t the implicit parameter of the method call
+ */
+ public TraceHandler(Object t)
+ {
+ target = t;
+ }
+
+ public Object invoke(Object proxy, Method m, Object[] args) throws Throwable
+ {
+ // print implicit argument
+ System.out.print(target);
+ // print method name
+ System.out.print("." + m.getName() + "(");
+ // print explicit arguments
+ if (args != null)
+ {
+ for (int i = 0; i < args.length; i++)
+ {
+ System.out.print(args[i]);
+ if (i < args.length - 1) System.out.print(", ");
+ }
+ }
+ System.out.println(")");
+
+ // invoke actual method
+ return m.invoke(target, args);
+ }
+
+ private Object target;
+}
diff --git a/volume1/v1ch06/StaticInnerClassTest/StaticInnerClassTest.java b/volume1/v1ch06/StaticInnerClassTest/StaticInnerClassTest.java
new file mode 100755
index 0000000..6e2524e
--- /dev/null
+++ b/volume1/v1ch06/StaticInnerClassTest/StaticInnerClassTest.java
@@ -0,0 +1,78 @@
+package StaticInnerClassTest;
+
+/**
+ * This program demonstrates the use of static inner classes.
+ * @version 1.01 2004-02-27
+ * @author Cay Horstmann
+ */
+public class StaticInnerClassTest
+{
+ public static void main(String[] args)
+ {
+ double[] d = new double[20];
+ for (int i = 0; i < d.length; i++)
+ d[i] = 100 * Math.random();
+ ArrayAlg.Pair p = ArrayAlg.minmax(d);
+ System.out.println("min = " + p.getFirst());
+ System.out.println("max = " + p.getSecond());
+ }
+}
+
+class ArrayAlg
+{
+ /**
+ * A pair of floating-point numbers
+ */
+ public static class Pair
+ {
+ /**
+ * Constructs a pair from two floating-point numbers
+ * @param f the first number
+ * @param s the second number
+ */
+ public Pair(double f, double s)
+ {
+ first = f;
+ second = s;
+ }
+
+ /**
+ * Returns the first number of the pair
+ * @return the first number
+ */
+ public double getFirst()
+ {
+ return first;
+ }
+
+ /**
+ * Returns the second number of the pair
+ * @return the second number
+ */
+ public double getSecond()
+ {
+ return second;
+ }
+
+ private double first;
+ private double second;
+ }
+
+ /**
+ * Computes both the minimum and the maximum of an array
+ * @param values an array of floating-point numbers
+ * @return a pair whose first element is the minimum and whose second element
+ * is the maximum
+ */
+ public static Pair minmax(double[] values)
+ {
+ double min = Double.MAX_VALUE;
+ double max = Double.MIN_VALUE;
+ for (double v : values)
+ {
+ if (min > v) min = v;
+ if (max < v) max = v;
+ }
+ return new Pair(min, max);
+ }
+}
diff --git a/volume1/v1ch06/TimerTest/TimerTest.java b/volume1/v1ch06/TimerTest/TimerTest.java
new file mode 100755
index 0000000..b076696
--- /dev/null
+++ b/volume1/v1ch06/TimerTest/TimerTest.java
@@ -0,0 +1,37 @@
+package TimerTest; /**
+ @version 1.00 2000-04-13
+ @author Cay Horstmann
+*/
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.Timer;
+// to resolve conflict with java.util.Timer
+
+public class TimerTest
+{
+ public static void main(String[] args)
+ {
+ ActionListener listener = new TimePrinter();
+
+ // construct a timer that calls the listener
+ // once every 10 seconds
+ Timer t = new Timer(10000, listener);
+ t.start();
+
+ JOptionPane.showMessageDialog(null, "Quit program?");
+ System.exit(0);
+ }
+}
+
+class TimePrinter implements ActionListener
+{
+ public void actionPerformed(ActionEvent event)
+ {
+ Date now = new Date();
+ System.out.println("At the tone, the time is " + now);
+ Toolkit.getDefaultToolkit().beep();
+ }
+}
diff --git a/volume1/v1ch06/v1ch06.iml b/volume1/v1ch06/v1ch06.iml
new file mode 100644
index 0000000..8021953
--- /dev/null
+++ b/volume1/v1ch06/v1ch06.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/volume1/v1ch12/GenericReflectionTest/GenericReflectionTest.java b/volume1/v1ch12/GenericReflectionTest/GenericReflectionTest.java
new file mode 100755
index 0000000..12e64b3
--- /dev/null
+++ b/volume1/v1ch12/GenericReflectionTest/GenericReflectionTest.java
@@ -0,0 +1,122 @@
+package GenericReflectionTest;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+/**
+ * @version 1.10 2007-05-15
+ * @author Cay Horstmann
+ */
+public class GenericReflectionTest
+{
+ public static void main(String[] args)
+ {
+ // read class name from command line args or user input
+ String name;
+ if (args.length > 0) name = args[0];
+ else
+ {
+ Scanner in = new Scanner(System.in);
+ System.out.println("Enter class name (e.g. java.util.Collections): ");
+ name = in.next();
+ }
+
+ try
+ {
+ // print generic info for class and public methods
+ Class> cl = Class.forName(name);
+ printClass(cl);
+ for (Method m : cl.getDeclaredMethods())
+ printMethod(m);
+ }
+ catch (ClassNotFoundException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ public static void printClass(Class> cl)
+ {
+ System.out.print(cl);
+ printTypes(cl.getTypeParameters(), "<", ", ", ">", true);
+ Type sc = cl.getGenericSuperclass();
+ if (sc != null)
+ {
+ System.out.print(" extends ");
+ printType(sc, false);
+ }
+ printTypes(cl.getGenericInterfaces(), " implements ", ", ", "", false);
+ System.out.println();
+ }
+
+ public static void printMethod(Method m)
+ {
+ String name = m.getName();
+ System.out.print(Modifier.toString(m.getModifiers()));
+ System.out.print(" ");
+ printTypes(m.getTypeParameters(), "<", ", ", "> ", true);
+
+ printType(m.getGenericReturnType(), false);
+ System.out.print(" ");
+ System.out.print(name);
+ System.out.print("(");
+ printTypes(m.getGenericParameterTypes(), "", ", ", "", false);
+ System.out.println(")");
+ }
+
+ public static void printTypes(Type[] types, String pre, String sep, String suf,
+ boolean isDefinition)
+ {
+ if (pre.equals(" extends ") && Arrays.equals(types, new Type[] { Object.class })) return;
+ if (types.length > 0) System.out.print(pre);
+ for (int i = 0; i < types.length; i++)
+ {
+ if (i > 0) System.out.print(sep);
+ printType(types[i], isDefinition);
+ }
+ if (types.length > 0) System.out.print(suf);
+ }
+
+ public static void printType(Type type, boolean isDefinition)
+ {
+ if (type instanceof Class)
+ {
+ Class> t = (Class>) type;
+ System.out.print(t.getName());
+ }
+ else if (type instanceof TypeVariable)
+ {
+ TypeVariable> t = (TypeVariable>) type;
+ System.out.print(t.getName());
+ if (isDefinition)
+ printTypes(t.getBounds(), " extends ", " & ", "", false);
+ }
+ else if (type instanceof WildcardType)
+ {
+ WildcardType t = (WildcardType) type;
+ System.out.print("?");
+ printTypes(t.getUpperBounds(), " extends ", " & ", "", false);
+ printTypes(t.getLowerBounds(), " super ", " & ", "", false);
+ }
+ else if (type instanceof ParameterizedType)
+ {
+ ParameterizedType t = (ParameterizedType) type;
+ Type owner = t.getOwnerType();
+ if (owner != null)
+ {
+ printType(owner, false);
+ System.out.print(".");
+ }
+ printType(t.getRawType(), false);
+ printTypes(t.getActualTypeArguments(), "<", ", ", ">", false);
+ }
+ else if (type instanceof GenericArrayType)
+ {
+ GenericArrayType t = (GenericArrayType) type;
+ System.out.print("");
+ printType(t.getGenericComponentType(), isDefinition);
+ System.out.print("[]");
+ }
+
+ }
+}
diff --git a/volume1/v1ch12/PairTest1/Pair.java b/volume1/v1ch12/PairTest1/Pair.java
new file mode 100755
index 0000000..2d63aaa
--- /dev/null
+++ b/volume1/v1ch12/PairTest1/Pair.java
@@ -0,0 +1,20 @@
+package PairTest1;
+
+/**
+ * @version 1.00 2004-05-10
+ * @author Cay Horstmann
+ */
+public class Pair
+{
+ public Pair() { first = null; second = null; }
+ public Pair(T first, T second) { this.first = first; this.second = second; }
+
+ public T getFirst() { return first; }
+ public T getSecond() { return second; }
+
+ public void setFirst(T newValue) { first = newValue; }
+ public void setSecond(T newValue) { second = newValue; }
+
+ private T first;
+ private T second;
+}
diff --git a/volume1/v1ch12/PairTest1/PairTest1.java b/volume1/v1ch12/PairTest1/PairTest1.java
new file mode 100755
index 0000000..ef5bbbe
--- /dev/null
+++ b/volume1/v1ch12/PairTest1/PairTest1.java
@@ -0,0 +1,37 @@
+package PairTest1;
+
+/**
+ * @version 1.00 2004-05-10
+ * @author Cay Horstmann
+ */
+public class PairTest1
+{
+ public static void main(String[] args)
+ {
+ String[] words = { "Mary", "had", "a", "little", "lamb" };
+ Pair mm = ArrayAlg.minmax(words);
+ System.out.println("min = " + mm.getFirst());
+ System.out.println("max = " + mm.getSecond());
+ }
+}
+
+class ArrayAlg
+{
+ /**
+ * Gets the minimum and maximum of an array of strings.
+ * @param a an array of strings
+ * @return a pair with the min and max value, or null if a is null or empty
+ */
+ public static Pair minmax(String[] a)
+ {
+ if (a == null || a.length == 0) return null;
+ String min = a[0];
+ String max = a[0];
+ for (int i = 1; i < a.length; i++)
+ {
+ if (min.compareTo(a[i]) > 0) min = a[i];
+ if (max.compareTo(a[i]) < 0) max = a[i];
+ }
+ return new Pair(min, max);
+ }
+}
diff --git a/volume1/v1ch12/PairTest2/Pair.java b/volume1/v1ch12/PairTest2/Pair.java
new file mode 100755
index 0000000..a5c5e07
--- /dev/null
+++ b/volume1/v1ch12/PairTest2/Pair.java
@@ -0,0 +1,20 @@
+package PairTest2;
+
+/**
+ * @version 1.00 2004-05-10
+ * @author Cay Horstmann
+ */
+public class Pair
+{
+ public Pair() { first = null; second = null; }
+ public Pair(T first, T second) { this.first = first; this.second = second; }
+
+ public T getFirst() { return first; }
+ public T getSecond() { return second; }
+
+ public void setFirst(T newValue) { first = newValue; }
+ public void setSecond(T newValue) { second = newValue; }
+
+ private T first;
+ private T second;
+}
diff --git a/volume1/v1ch12/PairTest2/PairTest2.java b/volume1/v1ch12/PairTest2/PairTest2.java
new file mode 100755
index 0000000..321bac6
--- /dev/null
+++ b/volume1/v1ch12/PairTest2/PairTest2.java
@@ -0,0 +1,46 @@
+package PairTest2;
+
+import java.util.*;
+
+/**
+ * @version 1.00 2004-05-10
+ * @author Cay Horstmann
+ */
+public class PairTest2
+{
+ public static void main(String[] args)
+ {
+ GregorianCalendar[] birthdays =
+ {
+ new GregorianCalendar(1906, Calendar.DECEMBER, 9), // G. Hopper
+ new GregorianCalendar(1815, Calendar.DECEMBER, 10), // A. Lovelace
+ new GregorianCalendar(1903, Calendar.DECEMBER, 3), // J. von Neumann
+ new GregorianCalendar(1910, Calendar.JUNE, 22), // K. Zuse
+ };
+ Pair mm = ArrayAlg.minmax(birthdays);
+ System.out.println("min = " + mm.getFirst().getTime());
+ System.out.println("max = " + mm.getSecond().getTime());
+ }
+}
+
+class ArrayAlg
+{
+ /**
+ Gets the minimum and maximum of an array of objects of type T.
+ @param a an array of objects of type T
+ @return a pair with the min and max value, or null if a is
+ null or empty
+ */
+ public static Pair minmax(T[] a)
+ {
+ if (a == null || a.length == 0) return null;
+ T min = a[0];
+ T max = a[0];
+ for (int i = 1; i < a.length; i++)
+ {
+ if (min.compareTo(a[i]) > 0) min = a[i];
+ if (max.compareTo(a[i]) < 0) max = a[i];
+ }
+ return new Pair(min, max);
+ }
+}
diff --git a/volume1/v1ch12/PairTest3/Pair.java b/volume1/v1ch12/PairTest3/Pair.java
new file mode 100755
index 0000000..0804be5
--- /dev/null
+++ b/volume1/v1ch12/PairTest3/Pair.java
@@ -0,0 +1,20 @@
+package PairTest3;
+
+/**
+ * @version 1.00 2004-05-10
+ * @author Cay Horstmann
+ */
+public class Pair
+{
+ public Pair() { first = null; second = null; }
+ public Pair(T first, T second) { this.first = first; this.second = second; }
+
+ public T getFirst() { return first; }
+ public T getSecond() { return second; }
+
+ public void setFirst(T newValue) { first = newValue; }
+ public void setSecond(T newValue) { second = newValue; }
+
+ private T first;
+ private T second;
+}
diff --git a/volume1/v1ch12/PairTest3/PairTest3.java b/volume1/v1ch12/PairTest3/PairTest3.java
new file mode 100755
index 0000000..6ae567b
--- /dev/null
+++ b/volume1/v1ch12/PairTest3/PairTest3.java
@@ -0,0 +1,145 @@
+package PairTest3;
+
+import java.util.*;
+
+/**
+ * @version 1.00 2004-05-10
+ * @author Cay Horstmann
+ */
+public class PairTest3
+{
+ public static void main(String[] args)
+ {
+ Manager ceo = new Manager("Gus Greedy", 800000, 2003, 12, 15);
+ Manager cfo = new Manager("Sid Sneaky", 600000, 2003, 12, 15);
+ Pair buddies = new Pair(ceo, cfo);
+ printBuddies(buddies);
+
+ ceo.setBonus(1000000);
+ cfo.setBonus(500000);
+ Manager[] managers = { ceo, cfo };
+
+ Pair result = new Pair();
+ minmaxBonus(managers, result);
+ System.out.println("first: " + result.getFirst().getName()
+ + ", second: " + result.getSecond().getName());
+ maxminBonus(managers, result);
+ System.out.println("first: " + result.getFirst().getName()
+ + ", second: " + result.getSecond().getName());
+ }
+
+ public static void printBuddies(Pair extends Employee> p)
+ {
+ Employee first = p.getFirst();
+ Employee second = p.getSecond();
+ System.out.println(first.getName() + " and " + second.getName() + " are buddies.");
+ }
+
+ public static void minmaxBonus(Manager[] a, Pair super Manager> result)
+ {
+ if (a == null || a.length == 0) return;
+ Manager min = a[0];
+ Manager max = a[0];
+ for (int i = 1; i < a.length; i++)
+ {
+ if (min.getBonus() > a[i].getBonus()) min = a[i];
+ if (max.getBonus() < a[i].getBonus()) max = a[i];
+ }
+ result.setFirst(min);
+ result.setSecond(max);
+ }
+
+ public static void maxminBonus(Manager[] a, Pair super Manager> result)
+ {
+ minmaxBonus(a, result);
+ PairAlg.swapHelper(result); // OK--swapHelper captures wildcard type
+ }
+}
+
+class PairAlg
+{
+ public static boolean hasNulls(Pair> p)
+ {
+ return p.getFirst() == null || p.getSecond() == null;
+ }
+
+ public static void swap(Pair> p) { swapHelper(p); }
+
+ public static void swapHelper(Pair p)
+ {
+ T t = p.getFirst();
+ p.setFirst(p.getSecond());
+ p.setSecond(t);
+ }
+}
+
+class Employee
+{
+ public Employee(String n, double s, int year, int month, int day)
+ {
+ name = n;
+ salary = s;
+ GregorianCalendar calendar = new GregorianCalendar(year, month - 1, day);
+ hireDay = calendar.getTime();
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public double getSalary()
+ {
+ return salary;
+ }
+
+ public Date getHireDay()
+ {
+ return hireDay;
+ }
+
+ public void raiseSalary(double byPercent)
+ {
+ double raise = salary * byPercent / 100;
+ salary += raise;
+ }
+
+ private String name;
+ private double salary;
+ private Date hireDay;
+}
+
+class Manager extends Employee
+{
+ /**
+ @param n the employee's name
+ @param s the salary
+ @param year the hire year
+ @param month the hire month
+ @param day the hire day
+ */
+ public Manager(String n, double s, int year, int month, int day)
+ {
+ super(n, s, year, month, day);
+ bonus = 0;
+ }
+
+ public double getSalary()
+ {
+ double baseSalary = super.getSalary();
+ return baseSalary + bonus;
+ }
+
+ public void setBonus(double b)
+ {
+ bonus = b;
+ }
+
+ public double getBonus()
+ {
+ return bonus;
+ }
+
+ private double bonus;
+}
+
diff --git a/volume1/v1ch12/v1ch12.iml b/volume1/v1ch12/v1ch12.iml
new file mode 100644
index 0000000..8021953
--- /dev/null
+++ b/volume1/v1ch12/v1ch12.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/volume1/v1ch13/CircularArrayQueueTest/CircularArrayQueueTest.java b/volume1/v1ch13/CircularArrayQueueTest/CircularArrayQueueTest.java
new file mode 100755
index 0000000..2075d15
--- /dev/null
+++ b/volume1/v1ch13/CircularArrayQueueTest/CircularArrayQueueTest.java
@@ -0,0 +1,124 @@
+package CircularArrayQueueTest;
+
+import java.util.*;
+
+/**
+ * This program demonstrates how to extend the collections framework.
+ * @version 1.20 2007-05-16
+ * @author Cay Horstmann
+ */
+public class CircularArrayQueueTest
+{
+ public static void main(String[] args)
+ {
+ Queue q = new CircularArrayQueue(5);
+ q.add("Amy");
+ q.add("Bob");
+ q.add("Carl");
+ q.add("Deedee");
+ q.add("Emile");
+ q.remove();
+ q.add("Fifi");
+ q.remove();
+ for (String s : q) System.out.println(s);
+ }
+}
+
+/**
+ A first-in, first-out bounded collection.
+*/
+class CircularArrayQueue extends AbstractQueue
+{
+ /**
+ Constructs an empty queue.
+ @param capacity the maximum capacity of the queue
+ */
+ public CircularArrayQueue(int capacity)
+ {
+ elements = new Object[capacity];
+ count = 0;
+ head = 0;
+ tail = 0;
+ }
+
+ public boolean offer(E newElement)
+ {
+ assert newElement != null;
+ if (count < elements.length)
+ {
+ elements[tail] = newElement;
+ tail = (tail + 1) % elements.length;
+ count++;
+ modcount++;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ public E poll()
+ {
+ if (count == 0) return null;
+ E r = peek();
+ head = (head + 1) % elements.length;
+ count--;
+ modcount++;
+ return r;
+ }
+
+ @SuppressWarnings("unchecked")
+ public E peek()
+ {
+ if (count == 0) return null;
+ return (E) elements[head];
+ }
+
+ public int size()
+ {
+ return count;
+ }
+
+ public Iterator iterator()
+ {
+ return new QueueIterator();
+
+ }
+
+ private class QueueIterator implements Iterator
+ {
+ public QueueIterator()
+ {
+ modcountAtConstruction = modcount;
+ }
+
+ @SuppressWarnings("unchecked")
+ public E next()
+ {
+ if (!hasNext()) throw new NoSuchElementException();
+ E r = (E) elements[(head + offset) % elements.length];
+ offset++;
+ return r;
+ }
+
+ public boolean hasNext()
+ {
+ if (modcount != modcountAtConstruction)
+ throw new ConcurrentModificationException();
+ return offset < count;
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ private int offset;
+ private int modcountAtConstruction;
+ }
+
+ private Object[] elements;
+ private int head;
+ private int tail;
+ private int count;
+ private int modcount;
+}
diff --git a/volume1/v1ch13/LinkedListTest/LinkedListTest.java b/volume1/v1ch13/LinkedListTest/LinkedListTest.java
new file mode 100755
index 0000000..d40100e
--- /dev/null
+++ b/volume1/v1ch13/LinkedListTest/LinkedListTest.java
@@ -0,0 +1,59 @@
+package LinkedListTest;
+
+import java.util.*;
+
+/**
+ * This program demonstrates operations on linked lists.
+ * @version 1.10 2004-08-02
+ * @author Cay Horstmann
+ */
+public class LinkedListTest
+{
+ public static void main(String[] args)
+ {
+ List a = new LinkedList();
+ a.add("Amy");
+ a.add("Carl");
+ a.add("Erica");
+
+ List b = new LinkedList();
+ b.add("Bob");
+ b.add("Doug");
+ b.add("Frances");
+ b.add("Gloria");
+
+ // merge the words from b into a
+
+ ListIterator aIter = a.listIterator();
+ Iterator bIter = b.iterator();
+
+ while (bIter.hasNext())
+ {
+ if (aIter.hasNext()) aIter.next();
+ aIter.add(bIter.next());
+ }
+
+ System.out.println(a);
+
+ // remove every second word from b
+
+ bIter = b.iterator();
+ while (bIter.hasNext())
+ {
+ bIter.next(); // skip one element
+ if (bIter.hasNext())
+ {
+ bIter.next(); // skip next element
+ bIter.remove(); // remove that element
+ }
+ }
+
+ System.out.println(b);
+
+ // bulk operation: remove all words in b from a
+
+ a.removeAll(b);
+
+ System.out.println(a);
+ }
+}
diff --git a/volume1/v1ch13/MapTest/MapTest.java b/volume1/v1ch13/MapTest/MapTest.java
new file mode 100755
index 0000000..4cae47c
--- /dev/null
+++ b/volume1/v1ch13/MapTest/MapTest.java
@@ -0,0 +1,69 @@
+package MapTest;
+
+import java.util.*;
+
+/**
+ * This program demonstrates the use of a map with key type String and value type Employee.
+ * @version 1.10 2004-08-02
+ * @author Cay Horstmann
+ */
+public class MapTest
+{
+ public static void main(String[] args)
+ {
+ Map staff = new HashMap();
+ staff.put("144-25-5464", new Employee("Amy Lee"));
+ staff.put("567-24-2546", new Employee("Harry Hacker"));
+ staff.put("157-62-7935", new Employee("Gary Cooper"));
+ staff.put("456-62-5527", new Employee("Francesca Cruz"));
+
+ // print all entries
+
+ System.out.println(staff);
+
+ // remove an entry
+
+ staff.remove("567-24-2546");
+
+ // replace an entry
+
+ staff.put("456-62-5527", new Employee("Francesca Miller"));
+
+ // look up a value
+
+ System.out.println(staff.get("157-62-7935"));
+
+ // iterate through all entries
+
+ for (Map.Entry entry : staff.entrySet())
+ {
+ String key = entry.getKey();
+ Employee value = entry.getValue();
+ System.out.println("key=" + key + ", value=" + value);
+ }
+ }
+}
+
+/**
+ * A minimalist employee class for testing purposes.
+ */
+class Employee
+{
+ /**
+ * Constructs an employee with $0 salary.
+ * @param n the employee name
+ */
+ public Employee(String n)
+ {
+ name = n;
+ salary = 0;
+ }
+
+ public String toString()
+ {
+ return "[name=" + name + ", salary=" + salary + "]";
+ }
+
+ private String name;
+ private double salary;
+}
diff --git a/volume1/v1ch13/PriorityQueueTest/PriorityQueueTest.java b/volume1/v1ch13/PriorityQueueTest/PriorityQueueTest.java
new file mode 100755
index 0000000..4bb614c
--- /dev/null
+++ b/volume1/v1ch13/PriorityQueueTest/PriorityQueueTest.java
@@ -0,0 +1,27 @@
+package PriorityQueueTest;
+
+import java.util.*;
+
+/**
+ * This program demonstrates the use of a priority queue.
+ * @version 1.00 2004-08-03
+ * @author Cay Horstmann
+ */
+public class PriorityQueueTest
+{
+ public static void main(String[] args)
+ {
+ PriorityQueue pq = new PriorityQueue();
+ pq.add(new GregorianCalendar(1906, Calendar.DECEMBER, 9)); // G. Hopper
+ pq.add(new GregorianCalendar(1815, Calendar.DECEMBER, 10)); // A. Lovelace
+ pq.add(new GregorianCalendar(1903, Calendar.DECEMBER, 3)); // J. von Neumann
+ pq.add(new GregorianCalendar(1910, Calendar.JUNE, 22)); // K. Zuse
+
+ System.out.println("Iterating over elements...");
+ for (GregorianCalendar date : pq)
+ System.out.println(date.get(Calendar.YEAR));
+ System.out.println("Removing elements...");
+ while (!pq.isEmpty())
+ System.out.println(pq.remove().get(Calendar.YEAR));
+ }
+}
diff --git a/volume1/v1ch13/SetTest/SetTest.java b/volume1/v1ch13/SetTest/SetTest.java
new file mode 100755
index 0000000..8c88236
--- /dev/null
+++ b/volume1/v1ch13/SetTest/SetTest.java
@@ -0,0 +1,33 @@
+package SetTest;
+
+import java.util.*;
+
+/**
+ * This program uses a set to print all unique words in System.in.
+ * @version 1.10 2003-08-02
+ * @author Cay Horstmann
+ */
+public class SetTest
+{
+ public static void main(String[] args)
+ {
+ Set words = new HashSet(); // HashSet implements Set
+ long totalTime = 0;
+
+ Scanner in = new Scanner(System.in);
+ while (in.hasNext())
+ {
+ String word = in.next();
+ long callTime = System.currentTimeMillis();
+ words.add(word);
+ callTime = System.currentTimeMillis() - callTime;
+ totalTime += callTime;
+ }
+
+ Iterator iter = words.iterator();
+ for (int i = 1; i <= 20; i++)
+ System.out.println(iter.next());
+ System.out.println(". . .");
+ System.out.println(words.size() + " distinct words. " + totalTime + " milliseconds.");
+ }
+}
diff --git a/volume1/v1ch13/ShuffleTest/ShuffleTest.java b/volume1/v1ch13/ShuffleTest/ShuffleTest.java
new file mode 100755
index 0000000..0e7a607
--- /dev/null
+++ b/volume1/v1ch13/ShuffleTest/ShuffleTest.java
@@ -0,0 +1,22 @@
+package ShuffleTest;
+
+import java.util.*;
+
+/**
+ * This program demonstrates the random shuffle and sort algorithms.
+ * @version 1.10 2004-08-02
+ * @author Cay Horstmann
+ */
+public class ShuffleTest
+{
+ public static void main(String[] args)
+ {
+ List numbers = new ArrayList();
+ for (int i = 1; i <= 49; i++)
+ numbers.add(i);
+ Collections.shuffle(numbers);
+ List winningCombination = numbers.subList(0, 6);
+ Collections.sort(winningCombination);
+ System.out.println(winningCombination);
+ }
+}
diff --git a/volume1/v1ch13/Sieve/Sieve.cpp b/volume1/v1ch13/Sieve/Sieve.cpp
new file mode 100755
index 0000000..fac6093
--- /dev/null
+++ b/volume1/v1ch13/Sieve/Sieve.cpp
@@ -0,0 +1,52 @@
+/**
+ @version 1.21 2004-08-03
+ @author Cay Horstmann
+*/
+
+#include
+#include
+#include
+
+using namespace std;
+
+int main()
+{
+ const int N = 2000000;
+ clock_t cstart = clock();
+
+ bitset b;
+ int count = 0;
+ int i;
+ for (i = 2; i <= N; i++)
+ b.set(i);
+ i = 2;
+ while (i * i <= N)
+ {
+ if (b.test(i))
+ {
+ count++;
+ int k = 2 * i;
+ while (k <= N)
+ {
+ b.reset(k);
+ k += i;
+ }
+ }
+ i++;
+ }
+ while (i <= N)
+ {
+ if (b.test(i))
+ count++;
+ i++;
+ }
+
+ clock_t cend = clock();
+ double millis = 1000.0
+ * (cend - cstart) / CLOCKS_PER_SEC;
+
+ cout << count << " primes\n"
+ << millis << " milliseconds\n";
+
+ return 0;
+}
diff --git a/volume1/v1ch13/Sieve/Sieve.java b/volume1/v1ch13/Sieve/Sieve.java
new file mode 100755
index 0000000..fcb04c9
--- /dev/null
+++ b/volume1/v1ch13/Sieve/Sieve.java
@@ -0,0 +1,45 @@
+package Sieve;
+
+import java.util.*;
+
+/**
+ * This program runs the Sieve of Erathostenes benchmark. It computes all primes up to 2,000,000.
+ * @version 1.21 2004-08-03
+ * @author Cay Horstmann
+ */
+public class Sieve
+{
+ public static void main(String[] s)
+ {
+ int n = 2000000;
+ long start = System.currentTimeMillis();
+ BitSet b = new BitSet(n + 1);
+ int count = 0;
+ int i;
+ for (i = 2; i <= n; i++)
+ b.set(i);
+ i = 2;
+ while (i * i <= n)
+ {
+ if (b.get(i))
+ {
+ count++;
+ int k = 2 * i;
+ while (k <= n)
+ {
+ b.clear(k);
+ k += i;
+ }
+ }
+ i++;
+ }
+ while (i <= n)
+ {
+ if (b.get(i)) count++;
+ i++;
+ }
+ long end = System.currentTimeMillis();
+ System.out.println(count + " primes");
+ System.out.println((end - start) + " milliseconds");
+ }
+}
diff --git a/volume1/v1ch13/Sieve/Sieve2.cpp b/volume1/v1ch13/Sieve/Sieve2.cpp
new file mode 100755
index 0000000..f5e2118
--- /dev/null
+++ b/volume1/v1ch13/Sieve/Sieve2.cpp
@@ -0,0 +1,69 @@
+/**
+ @version 1.21 2004-08-03
+ @author Cay Horstmann
+*/
+
+/**
+ This program runs the Sieve of Erathostenes benchmark,
+ using a handwritten BitSet class instead of the library class.
+ It computes all primes up to 2,000,000.
+*/
+
+#include
+#include
+
+using namespace std;
+
+template
+class bitset
+{
+public:
+ bitset() : bits(new char[(N - 1) / 8 + 1]) {}
+ bool test(int n) { return (bits[n >> 3] & (1 << (n & 7))) != 0; }
+ void set(int n) { bits[n >> 3] |= 1 << (n & 7); }
+ void reset(int n) { bits[n >> 3] &= ~(1 << (n & 7)); }
+private:
+ char* bits;
+};
+
+int main()
+{
+ const int N = 2000000;
+ clock_t cstart = clock();
+
+ bitset b;
+ int count = 0;
+ int i;
+ for (i = 2; i <= N; i++)
+ b.set(i);
+ i = 2;
+ while (i * i <= N)
+ {
+ if (b.test(i))
+ {
+ count++;
+ int k = 2 * i;
+ while (k <= N)
+ {
+ b.reset(k);
+ k += i;
+ }
+ }
+ i++;
+ }
+ while (i <= N)
+ {
+ if (b.test(i))
+ count++;
+ i++;
+ }
+
+ clock_t cend = clock();
+ double millis = 1000.0
+ * (cend - cstart) / CLOCKS_PER_SEC;
+
+ cout << count << " primes\n"
+ << millis << " milliseconds\n";
+
+ return 0;
+}
diff --git a/volume1/v1ch13/TreeSetTest/TreeSetTest.java b/volume1/v1ch13/TreeSetTest/TreeSetTest.java
new file mode 100755
index 0000000..014c79f
--- /dev/null
+++ b/volume1/v1ch13/TreeSetTest/TreeSetTest.java
@@ -0,0 +1,94 @@
+package TreeSetTest;
+
+/**
+ @version 1.10 2004-08-02
+ @author Cay Horstmann
+*/
+
+import java.util.*;
+
+/**
+ This program sorts a set of item by comparing
+ their descriptions.
+*/
+public class TreeSetTest
+{
+ public static void main(String[] args)
+ {
+ SortedSet- parts = new TreeSet
- ();
+ parts.add(new Item("Toaster", 1234));
+ parts.add(new Item("Widget", 4562));
+ parts.add(new Item("Modem", 9912));
+ System.out.println(parts);
+
+ SortedSet
- sortByDescription = new TreeSet
- (new
+ Comparator
- ()
+ {
+ public int compare(Item a, Item b)
+ {
+ String descrA = a.getDescription();
+ String descrB = b.getDescription();
+ return descrA.compareTo(descrB);
+ }
+ });
+
+ sortByDescription.addAll(parts);
+ System.out.println(sortByDescription);
+ }
+}
+
+/**
+ An item with a description and a part number.
+*/
+class Item implements Comparable
-
+{
+ /**
+ Constructs an item.
+ @param aDescription the item's description
+ @param aPartNumber the item's part number
+ */
+ public Item(String aDescription, int aPartNumber)
+ {
+ description = aDescription;
+ partNumber = aPartNumber;
+ }
+
+ /**
+ Gets the description of this item.
+ @return the description
+ */
+ public String getDescription()
+ {
+ return description;
+ }
+
+ public String toString()
+ {
+ return "[descripion=" + description
+ + ", partNumber=" + partNumber + "]";
+ }
+
+ public boolean equals(Object otherObject)
+ {
+ if (this == otherObject) return true;
+ if (otherObject == null) return false;
+ if (getClass() != otherObject.getClass()) return false;
+ Item other = (Item) otherObject;
+ return description.equals(other.description)
+ && partNumber == other.partNumber;
+ }
+
+ public int hashCode()
+ {
+ return 13 * description.hashCode() + 17 * partNumber;
+ }
+
+ public int compareTo(Item other)
+ {
+ return partNumber - other.partNumber;
+ }
+
+ private String description;
+ private int partNumber;
+}
+
diff --git a/volume1/v1ch13/v1ch13.iml b/volume1/v1ch13/v1ch13.iml
new file mode 100644
index 0000000..8021953
--- /dev/null
+++ b/volume1/v1ch13/v1ch13.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/volume1/v1ch14/AlgorithmAnimation/AlgorithmAnimation.java b/volume1/v1ch14/AlgorithmAnimation/AlgorithmAnimation.java
new file mode 100755
index 0000000..cd156aa
--- /dev/null
+++ b/volume1/v1ch14/AlgorithmAnimation/AlgorithmAnimation.java
@@ -0,0 +1,182 @@
+package AlgorithmAnimation;
+
+import java.awt.*;
+import java.awt.geom.*;
+import java.awt.event.*;
+import java.util.*;
+import java.util.concurrent.*;
+import javax.swing.*;
+
+/**
+ * This program animates a sort algorithm.
+ * @version 1.01 2007-05-18
+ * @author Cay Horstmann
+ */
+public class AlgorithmAnimation
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ JFrame frame = new AnimationFrame();
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ }
+ });
+ }
+}
+
+/**
+ * This frame shows the array as it is sorted, together with buttons to single-step the animation or
+ * to run it without interruption.
+ */
+class AnimationFrame extends JFrame
+{
+ public AnimationFrame()
+ {
+ ArrayComponent comp = new ArrayComponent();
+ add(comp, BorderLayout.CENTER);
+
+ final Sorter sorter = new Sorter(comp);
+
+ JButton runButton = new JButton("Run");
+ runButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ sorter.setRun();
+ }
+ });
+
+ JButton stepButton = new JButton("Step");
+ stepButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ sorter.setStep();
+ }
+ });
+
+ JPanel buttons = new JPanel();
+ buttons.add(runButton);
+ buttons.add(stepButton);
+ add(buttons, BorderLayout.NORTH);
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ Thread t = new Thread(sorter);
+ t.start();
+ }
+
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 300;
+}
+
+/**
+ * This runnable executes a sort algorithm. When two elements are compared, the algorithm pauses and
+ * updates a component.
+ */
+class Sorter implements Runnable
+{
+ /**
+ * Constructs a Sorter.
+
+ * @param comp the component on which to display the sorting progress
+ */
+ public Sorter(ArrayComponent comp)
+ {
+ values = new Double[VALUES_LENGTH];
+ for (int i = 0; i < values.length; i++)
+ values[i] = new Double(Math.random());
+ this.component = comp;
+ this.gate = new Semaphore(1);
+ this.run = false;
+ }
+
+ /**
+ * Sets the sorter to "run" mode. Called on the event dispatch thread.
+ */
+ public void setRun()
+ {
+ run = true;
+ gate.release();
+ }
+
+ /**
+ * Sets the sorter to "step" mode. Called on the event dispatch thread.
+ */
+ public void setStep()
+ {
+ run = false;
+ gate.release();
+ }
+
+ public void run()
+ {
+ Comparator comp = new Comparator()
+ {
+ public int compare(Double i1, Double i2)
+ {
+ component.setValues(values, i1, i2);
+ try
+ {
+ if (run) Thread.sleep(DELAY);
+ else gate.acquire();
+ }
+ catch (InterruptedException exception)
+ {
+ Thread.currentThread().interrupt();
+ }
+ return i1.compareTo(i2);
+ }
+ };
+ Arrays.sort(values, comp);
+ component.setValues(values, null, null);
+ }
+
+ private Double[] values;
+ private ArrayComponent component;
+ private Semaphore gate;
+ private static final int DELAY = 100;
+ private volatile boolean run;
+ private static final int VALUES_LENGTH = 30;
+}
+
+/**
+ * This component draws an array and marks two elements in the array.
+ */
+class ArrayComponent extends JComponent
+{
+ /**
+ * Sets the values to be painted. Called on the sorter thread.
+ * @param values the array of values to display
+ * @param marked1 the first marked element
+ * @param marked2 the second marked element
+ */
+ public synchronized void setValues(Double[] values, Double marked1, Double marked2)
+ {
+ this.values = values.clone();
+ this.marked1 = marked1;
+ this.marked2 = marked2;
+ repaint();
+ }
+
+ public synchronized void paintComponent(Graphics g) // Called on the event dispatch thread
+ {
+ if (values == null) return;
+ Graphics2D g2 = (Graphics2D) g;
+ int width = getWidth() / values.length;
+ for (int i = 0; i < values.length; i++)
+ {
+ double height = values[i] * getHeight();
+ Rectangle2D bar = new Rectangle2D.Double(width * i, 0, width, height);
+ if (values[i] == marked1 || values[i] == marked2) g2.fill(bar);
+ else g2.draw(bar);
+ }
+ }
+
+ private Double marked1;
+ private Double marked2;
+ private Double[] values;
+}
diff --git a/volume1/v1ch14/BlockingQueueTest/BlockingQueueTest.java b/volume1/v1ch14/BlockingQueueTest/BlockingQueueTest.java
new file mode 100755
index 0000000..8670424
--- /dev/null
+++ b/volume1/v1ch14/BlockingQueueTest/BlockingQueueTest.java
@@ -0,0 +1,142 @@
+package BlockingQueueTest;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+/**
+ * @version 1.0 2004-08-01
+ * @author Cay Horstmann
+ */
+public class BlockingQueueTest
+{
+ public static void main(String[] args)
+ {
+ Scanner in = new Scanner(System.in);
+ System.out.print("Enter base directory (e.g. /usr/local/jdk1.6.0/src): ");
+ String directory = in.nextLine();
+ System.out.print("Enter keyword (e.g. volatile): ");
+ String keyword = in.nextLine();
+
+ final int FILE_QUEUE_SIZE = 10;
+ final int SEARCH_THREADS = 100;
+
+ BlockingQueue queue = new ArrayBlockingQueue(FILE_QUEUE_SIZE);
+
+ FileEnumerationTask enumerator = new FileEnumerationTask(queue, new File(directory));
+ new Thread(enumerator).start();
+ for (int i = 1; i <= SEARCH_THREADS; i++)
+ new Thread(new SearchTask(queue, keyword)).start();
+ }
+}
+
+/**
+ * This task enumerates all files in a directory and its subdirectories.
+ */
+class FileEnumerationTask implements Runnable
+{
+ /**
+ * Constructs a FileEnumerationTask.
+ * @param queue the blocking queue to which the enumerated files are added
+ * @param startingDirectory the directory in which to start the enumeration
+ */
+ public FileEnumerationTask(BlockingQueue queue, File startingDirectory)
+ {
+ this.queue = queue;
+ this.startingDirectory = startingDirectory;
+ }
+
+ public void run()
+ {
+ try
+ {
+ enumerate(startingDirectory);
+ queue.put(DUMMY);
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+
+ /**
+ * Recursively enumerates all files in a given directory and its subdirectories
+ * @param directory the directory in which to start
+ */
+ public void enumerate(File directory) throws InterruptedException
+ {
+ File[] files = directory.listFiles();
+ for (File file : files)
+ {
+ if (file.isDirectory()) enumerate(file);
+ else queue.put(file);
+ }
+ }
+
+ public static File DUMMY = new File("");
+
+ private BlockingQueue queue;
+ private File startingDirectory;
+}
+
+/**
+ * This task searches files for a given keyword.
+ */
+class SearchTask implements Runnable
+{
+ /**
+ * Constructs a SearchTask.
+ * @param queue the queue from which to take files
+ * @param keyword the keyword to look for
+ */
+ public SearchTask(BlockingQueue queue, String keyword)
+ {
+ this.queue = queue;
+ this.keyword = keyword;
+ }
+
+ public void run()
+ {
+ try
+ {
+ boolean done = false;
+ while (!done)
+ {
+ File file = queue.take();
+ if (file == FileEnumerationTask.DUMMY)
+ {
+ queue.put(file);
+ done = true;
+ }
+ else search(file);
+ }
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+
+ /**
+ * Searches a file for a given keyword and prints all matching lines.
+ * @param file the file to search
+ */
+ public void search(File file) throws IOException
+ {
+ Scanner in = new Scanner(new FileInputStream(file));
+ int lineNumber = 0;
+ while (in.hasNextLine())
+ {
+ lineNumber++;
+ String line = in.nextLine();
+ if (line.contains(keyword)) System.out.printf("%s:%d:%s%n", file.getPath(), lineNumber,
+ line);
+ }
+ in.close();
+ }
+
+ private BlockingQueue queue;
+ private String keyword;
+}
diff --git a/volume1/v1ch14/Bounce/Ball.java b/volume1/v1ch14/Bounce/Ball.java
new file mode 100755
index 0000000..8d0d04c
--- /dev/null
+++ b/volume1/v1ch14/Bounce/Ball.java
@@ -0,0 +1,55 @@
+package Bounce;
+
+import java.awt.geom.*;
+
+/**
+ * A ball that moves and bounces off the edges of a rectangle
+ * @version 1.33 2007-05-17
+ * @author Cay Horstmann
+ */
+public class Ball
+{
+ /**
+ * Moves the ball to the next position, reversing direction if it hits one of the edges
+ */
+ public void move(Rectangle2D bounds)
+ {
+ x += dx;
+ y += dy;
+ if (x < bounds.getMinX())
+ {
+ x = bounds.getMinX();
+ dx = -dx;
+ }
+ if (x + XSIZE >= bounds.getMaxX())
+ {
+ x = bounds.getMaxX() - XSIZE;
+ dx = -dx;
+ }
+ if (y < bounds.getMinY())
+ {
+ y = bounds.getMinY();
+ dy = -dy;
+ }
+ if (y + YSIZE >= bounds.getMaxY())
+ {
+ y = bounds.getMaxY() - YSIZE;
+ dy = -dy;
+ }
+ }
+
+ /**
+ * Gets the shape of the ball at its current position.
+ */
+ public Ellipse2D getShape()
+ {
+ return new Ellipse2D.Double(x, y, XSIZE, YSIZE);
+ }
+
+ private static final int XSIZE = 15;
+ private static final int YSIZE = 15;
+ private double x = 0;
+ private double y = 0;
+ private double dx = 1;
+ private double dy = 1;
+}
diff --git a/volume1/v1ch14/Bounce/BallComponent.java b/volume1/v1ch14/Bounce/BallComponent.java
new file mode 100755
index 0000000..c68ccbb
--- /dev/null
+++ b/volume1/v1ch14/Bounce/BallComponent.java
@@ -0,0 +1,35 @@
+package Bounce;
+
+import java.awt.*;
+import java.util.*;
+import javax.swing.*;
+
+/**
+ * The component that draws the balls.
+ * @version 1.33 2007-05-17
+ * @author Cay Horstmann
+ */
+public class BallComponent extends JPanel
+{
+ /**
+ * Add a ball to the component.
+ * @param b the ball to add
+ */
+ public void add(Ball b)
+ {
+ balls.add(b);
+ }
+
+ public void paintComponent(Graphics g)
+ {
+ super.paintComponent(g); // erase background
+ Graphics2D g2 = (Graphics2D) g;
+ for (Ball b : balls)
+ {
+ g2.fill(b.getShape());
+ }
+ }
+
+ private ArrayList balls = new ArrayList();
+}
+
diff --git a/volume1/v1ch14/Bounce/Bounce.java b/volume1/v1ch14/Bounce/Bounce.java
new file mode 100755
index 0000000..b074877
--- /dev/null
+++ b/volume1/v1ch14/Bounce/Bounce.java
@@ -0,0 +1,103 @@
+package Bounce;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+/**
+ * Shows an animated bouncing ball.
+ * @version 1.33 2007-05-17
+ * @author Cay Horstmann
+ */
+public class Bounce
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ JFrame frame = new BounceFrame();
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ }
+ });
+ }
+}
+
+/**
+ * The frame with ball component and buttons.
+ */
+class BounceFrame extends JFrame
+{
+ /**
+ * Constructs the frame with the component for showing the bouncing ball and Start and Close
+ * buttons
+ */
+ public BounceFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+ setTitle("Bounce");
+
+ comp = new BallComponent();
+ add(comp, BorderLayout.CENTER);
+ JPanel buttonPanel = new JPanel();
+ addButton(buttonPanel, "Start", new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ addBall();
+ }
+ });
+
+ addButton(buttonPanel, "Close", new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ System.exit(0);
+ }
+ });
+ add(buttonPanel, BorderLayout.SOUTH);
+ }
+
+ /**
+ * Adds a button to a container.
+ * @param c the container
+ * @param title the button title
+ * @param listener the action listener for the button
+ */
+ public void addButton(Container c, String title, ActionListener listener)
+ {
+ JButton button = new JButton(title);
+ c.add(button);
+ button.addActionListener(listener);
+ }
+
+ /**
+ * Adds a bouncing ball to the panel and makes it bounce 1,000 times.
+ */
+ public void addBall()
+ {
+ try
+ {
+ Ball ball = new Ball();
+ comp.add(ball);
+
+ for (int i = 1; i <= STEPS; i++)
+ {
+ ball.move(comp.getBounds());
+ comp.paint(comp.getGraphics());
+ Thread.sleep(DELAY);
+ }
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+
+ private BallComponent comp;
+ public static final int DEFAULT_WIDTH = 450;
+ public static final int DEFAULT_HEIGHT = 350;
+ public static final int STEPS = 1000;
+ public static final int DELAY = 3;
+}
\ No newline at end of file
diff --git a/volume1/v1ch14/BounceThread/Ball.java b/volume1/v1ch14/BounceThread/Ball.java
new file mode 100755
index 0000000..b0b05c9
--- /dev/null
+++ b/volume1/v1ch14/BounceThread/Ball.java
@@ -0,0 +1,57 @@
+package BounceThread;
+
+import java.awt.geom.*;
+
+/**
+ A ball that moves and bounces off the edges of a
+ rectangle
+ * @version 1.33 2007-05-17
+ * @author Cay Horstmann
+*/
+public class Ball
+{
+ /**
+ Moves the ball to the next position, reversing direction
+ if it hits one of the edges
+ */
+ public void move(Rectangle2D bounds)
+ {
+ x += dx;
+ y += dy;
+ if (x < bounds.getMinX())
+ {
+ x = bounds.getMinX();
+ dx = -dx;
+ }
+ if (x + XSIZE >= bounds.getMaxX())
+ {
+ x = bounds.getMaxX() - XSIZE;
+ dx = -dx;
+ }
+ if (y < bounds.getMinY())
+ {
+ y = bounds.getMinY();
+ dy = -dy;
+ }
+ if (y + YSIZE >= bounds.getMaxY())
+ {
+ y = bounds.getMaxY() - YSIZE;
+ dy = -dy;
+ }
+ }
+
+ /**
+ Gets the shape of the ball at its current position.
+ */
+ public Ellipse2D getShape()
+ {
+ return new Ellipse2D.Double(x, y, XSIZE, YSIZE);
+ }
+
+ private static final int XSIZE = 15;
+ private static final int YSIZE = 15;
+ private double x = 0;
+ private double y = 0;
+ private double dx = 1;
+ private double dy = 1;
+}
diff --git a/volume1/v1ch14/BounceThread/BallComponent.java b/volume1/v1ch14/BounceThread/BallComponent.java
new file mode 100755
index 0000000..863d93a
--- /dev/null
+++ b/volume1/v1ch14/BounceThread/BallComponent.java
@@ -0,0 +1,34 @@
+package BounceThread;
+
+import java.awt.*;
+import java.util.*;
+import javax.swing.*;
+
+/**
+ * The component that draws the balls.
+ * @version 1.33 2007-05-17
+ * @author Cay Horstmann
+ */
+public class BallComponent extends JComponent
+{
+ /**
+ * Add a ball to the panel.
+ * @param b the ball to add
+ */
+ public void add(Ball b)
+ {
+ balls.add(b);
+ }
+
+ public void paintComponent(Graphics g)
+ {
+ Graphics2D g2 = (Graphics2D) g;
+ for (Ball b : balls)
+ {
+ g2.fill(b.getShape());
+ }
+ }
+
+ private ArrayList balls = new ArrayList();
+}
+
diff --git a/volume1/v1ch14/BounceThread/BounceThread.java b/volume1/v1ch14/BounceThread/BounceThread.java
new file mode 100755
index 0000000..dd8081e
--- /dev/null
+++ b/volume1/v1ch14/BounceThread/BounceThread.java
@@ -0,0 +1,131 @@
+package BounceThread;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+/**
+ * Shows animated bouncing balls.
+ * @version 1.33 2007-05-17
+ * @author Cay Horstmann
+ */
+public class BounceThread
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ JFrame frame = new BounceFrame();
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ }
+ });
+ }
+}
+
+/**
+ * A runnable that animates a bouncing ball.
+ */
+class BallRunnable implements Runnable
+{
+ /**
+ * Constructs the runnable.
+ * @aBall the ball to bounce
+ * @aPanel the component in which the ball bounces
+ */
+ public BallRunnable(Ball aBall, Component aComponent)
+ {
+ ball = aBall;
+ component = aComponent;
+ }
+
+ public void run()
+ {
+ try
+ {
+ for (int i = 1; i <= STEPS; i++)
+ {
+ ball.move(component.getBounds());
+ component.repaint();
+ Thread.sleep(DELAY);
+ }
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+
+ private Ball ball;
+ private Component component;
+ public static final int STEPS = 1000;
+ public static final int DELAY = 5;
+}
+
+/**
+ * The frame with panel and buttons.
+ */
+class BounceFrame extends JFrame
+{
+ /**
+ * Constructs the frame with the component for showing the bouncing ball and Start and Close
+ * buttons
+ */
+ public BounceFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+ setTitle("BounceThread");
+
+ comp = new BallComponent();
+ add(comp, BorderLayout.CENTER);
+ JPanel buttonPanel = new JPanel();
+ addButton(buttonPanel, "Start", new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ addBall();
+ }
+ });
+
+ addButton(buttonPanel, "Close", new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ System.exit(0);
+ }
+ });
+ add(buttonPanel, BorderLayout.SOUTH);
+ }
+
+ /**
+ * Adds a button to a container.
+ * @param c the container
+ * @param title the button title
+ * @param listener the action listener for the button
+ */
+ public void addButton(Container c, String title, ActionListener listener)
+ {
+ JButton button = new JButton(title);
+ c.add(button);
+ button.addActionListener(listener);
+ }
+
+ /**
+ * Adds a bouncing ball to the canvas and starts a thread to make it bounce
+ */
+ public void addBall()
+ {
+ Ball b = new Ball();
+ comp.add(b);
+ Runnable r = new BallRunnable(b, comp);
+ Thread t = new Thread(r);
+ t.start();
+ }
+
+ private BallComponent comp;
+ public static final int DEFAULT_WIDTH = 450;
+ public static final int DEFAULT_HEIGHT = 350;
+ public static final int STEPS = 1000;
+ public static final int DELAY = 3;
+}
diff --git a/volume1/v1ch14/FutureTest/FutureTest.java b/volume1/v1ch14/FutureTest/FutureTest.java
new file mode 100755
index 0000000..46efac9
--- /dev/null
+++ b/volume1/v1ch14/FutureTest/FutureTest.java
@@ -0,0 +1,121 @@
+package FutureTest;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+/**
+ * @version 1.0 2004-08-01
+ * @author Cay Horstmann
+ */
+public class FutureTest
+{
+ public static void main(String[] args)
+ {
+ Scanner in = new Scanner(System.in);
+ System.out.print("Enter base directory (e.g. /usr/local/jdk5.0/src): ");
+ String directory = in.nextLine();
+ System.out.print("Enter keyword (e.g. volatile): ");
+ String keyword = in.nextLine();
+
+ MatchCounter counter = new MatchCounter(new File(directory), keyword);
+ FutureTask task = new FutureTask(counter);
+ Thread t = new Thread(task);
+ t.start();
+ try
+ {
+ System.out.println(task.get() + " matching files.");
+ }
+ catch (ExecutionException e)
+ {
+ e.printStackTrace();
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+}
+
+/**
+ * This task counts the files in a directory and its subdirectories that contain a given keyword.
+ */
+class MatchCounter implements Callable
+{
+ /**
+ * Constructs a MatchCounter.
+ * @param directory the directory in which to start the search
+ * @param keyword the keyword to look for
+ */
+ public MatchCounter(File directory, String keyword)
+ {
+ this.directory = directory;
+ this.keyword = keyword;
+ }
+
+ public Integer call()
+ {
+ count = 0;
+ try
+ {
+ File[] files = directory.listFiles();
+ ArrayList> results = new ArrayList>();
+
+ for (File file : files)
+ if (file.isDirectory())
+ {
+ MatchCounter counter = new MatchCounter(file, keyword);
+ FutureTask task = new FutureTask(counter);
+ results.add(task);
+ Thread t = new Thread(task);
+ t.start();
+ }
+ else
+ {
+ if (search(file)) count++;
+ }
+
+ for (Future result : results)
+ try
+ {
+ count += result.get();
+ }
+ catch (ExecutionException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ catch (InterruptedException e)
+ {
+ }
+ return count;
+ }
+
+ /**
+ * Searches a file for a given keyword.
+ * @param file the file to search
+ * @return true if the keyword is contained in the file
+ */
+ public boolean search(File file)
+ {
+ try
+ {
+ Scanner in = new Scanner(new FileInputStream(file));
+ boolean found = false;
+ while (!found && in.hasNextLine())
+ {
+ String line = in.nextLine();
+ if (line.contains(keyword)) found = true;
+ }
+ in.close();
+ return found;
+ }
+ catch (IOException e)
+ {
+ return false;
+ }
+ }
+
+ private File directory;
+ private String keyword;
+ private int count;
+}
diff --git a/volume1/v1ch14/SwingThreadTest/SwingThreadTest.java b/volume1/v1ch14/SwingThreadTest/SwingThreadTest.java
new file mode 100755
index 0000000..da386d4
--- /dev/null
+++ b/volume1/v1ch14/SwingThreadTest/SwingThreadTest.java
@@ -0,0 +1,145 @@
+package SwingThreadTest;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates that a thread that runs in parallel with the event dispatch thread can
+ * cause errors in Swing components.
+ * @version 1.23 2007-05-17
+ * @author Cay Horstmann
+ */
+public class SwingThreadTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ SwingThreadFrame frame = new SwingThreadFrame();
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ }
+ });
+ }
+}
+
+/**
+ * This frame has two buttons to fill a combo box from a separate thread. The "Good" button uses the
+ * event queue, the "Bad" button modifies the combo box directly.
+ */
+class SwingThreadFrame extends JFrame
+{
+ public SwingThreadFrame()
+ {
+ setTitle("SwingThreadTest");
+
+ final JComboBox combo = new JComboBox();
+ combo.insertItemAt(Integer.MAX_VALUE, 0);
+ combo.setPrototypeDisplayValue(combo.getItemAt(0));
+ combo.setSelectedIndex(0);
+
+ JPanel panel = new JPanel();
+
+ JButton goodButton = new JButton("Good");
+ goodButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ new Thread(new GoodWorkerRunnable(combo)).start();
+ }
+ });
+ panel.add(goodButton);
+ JButton badButton = new JButton("Bad");
+ badButton.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ new Thread(new BadWorkerRunnable(combo)).start();
+ }
+ });
+ panel.add(badButton);
+
+ panel.add(combo);
+ add(panel);
+ pack();
+ }
+}
+
+/**
+ * This runnable modifies a combo box by randomly adding and removing numbers. This can result in
+ * errors because the combo box methods are not synchronized and both the worker thread and the
+ * event dispatch thread access the combo box.
+ */
+class BadWorkerRunnable implements Runnable
+{
+ public BadWorkerRunnable(JComboBox aCombo)
+ {
+ combo = aCombo;
+ generator = new Random();
+ }
+
+ public void run()
+ {
+ try
+ {
+ while (true)
+ {
+ int i = Math.abs(generator.nextInt());
+ if (i % 2 == 0) combo.insertItemAt(i, 0);
+ else if (combo.getItemCount() > 0) combo.removeItemAt(i % combo.getItemCount());
+ Thread.sleep(1);
+ }
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+
+ private JComboBox combo;
+ private Random generator;
+}
+
+/**
+ * This runnable modifies a combo box by randomly adding and removing numbers. In order to ensure
+ * that the combo box is not corrupted, the editing operations are forwarded to the event dispatch
+ * thread.
+ */
+class GoodWorkerRunnable implements Runnable
+{
+ public GoodWorkerRunnable(JComboBox aCombo)
+ {
+ combo = aCombo;
+ generator = new Random();
+ }
+
+ public void run()
+ {
+ try
+ {
+ while (true)
+ {
+ EventQueue.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ int i = Math.abs(generator.nextInt());
+ if (i % 2 == 0) combo.insertItemAt(i, 0);
+ else if (combo.getItemCount() > 0) combo.removeItemAt(i
+ % combo.getItemCount());
+ }
+ });
+ Thread.sleep(1);
+ }
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+
+ private JComboBox combo;
+ private Random generator;
+}
\ No newline at end of file
diff --git a/volume1/v1ch14/SwingWorkerTest/SwingWorkerTest.java b/volume1/v1ch14/SwingWorkerTest/SwingWorkerTest.java
new file mode 100755
index 0000000..c262d19
--- /dev/null
+++ b/volume1/v1ch14/SwingWorkerTest/SwingWorkerTest.java
@@ -0,0 +1,180 @@
+package SwingWorkerTest;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import java.util.List;
+import java.util.concurrent.*;
+
+import javax.swing.*;
+
+/**
+ * This program demonstrates a worker thread that runs a potentially time-consuming task.
+ * @version 1.1 2007-05-18
+ * @author Cay Horstmann
+ */
+public class SwingWorkerTest
+{
+ public static void main(String[] args) throws Exception
+ {
+ EventQueue.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ JFrame frame = new SwingWorkerFrame();
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ }
+ });
+ }
+}
+
+/**
+ * This frame has a text area to show the contents of a text file, a menu to open a file and cancel
+ * the opening process, and a status line to show the file loading progress.
+ */
+class SwingWorkerFrame extends JFrame
+{
+ public SwingWorkerFrame()
+ {
+ chooser = new JFileChooser();
+ chooser.setCurrentDirectory(new File("."));
+
+ textArea = new JTextArea();
+ add(new JScrollPane(textArea));
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ statusLine = new JLabel(" ");
+ add(statusLine, BorderLayout.SOUTH);
+
+ JMenuBar menuBar = new JMenuBar();
+ setJMenuBar(menuBar);
+
+ JMenu menu = new JMenu("File");
+ menuBar.add(menu);
+
+ openItem = new JMenuItem("Open");
+ menu.add(openItem);
+ openItem.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ // show file chooser dialog
+ int result = chooser.showOpenDialog(null);
+
+ // if file selected, set it as icon of the label
+ if (result == JFileChooser.APPROVE_OPTION)
+ {
+ textArea.setText("");
+ openItem.setEnabled(false);
+ textReader = new TextReader(chooser.getSelectedFile());
+ textReader.execute();
+ cancelItem.setEnabled(true);
+ }
+ }
+ });
+
+ cancelItem = new JMenuItem("Cancel");
+ menu.add(cancelItem);
+ cancelItem.setEnabled(false);
+ cancelItem.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ textReader.cancel(true);
+ }
+ });
+ }
+
+ private class ProgressData
+ {
+ public int number;
+ public String line;
+ }
+
+ private class TextReader extends SwingWorker
+ {
+ public TextReader(File file)
+ {
+ this.file = file;
+ }
+
+ // the following method executes in the worker thread; it doesn't touch Swing components
+
+ @Override
+ public StringBuilder doInBackground() throws IOException, InterruptedException
+ {
+ int lineNumber = 0;
+ Scanner in = new Scanner(new FileInputStream(file));
+ while (in.hasNextLine())
+ {
+ String line = in.nextLine();
+ lineNumber++;
+ text.append(line);
+ text.append("\n");
+ ProgressData data = new ProgressData();
+ data.number = lineNumber;
+ data.line = line;
+ publish(data);
+ Thread.sleep(1); // to test cancellation; no need to do this in your programs
+ }
+ return text;
+ }
+
+ // the following methods execute in the event dispatch thread
+
+ @Override
+ public void process(List data)
+ {
+ if (isCancelled()) return;
+ StringBuilder b = new StringBuilder();
+ statusLine.setText("" + data.get(data.size() - 1).number);
+ for (ProgressData d : data)
+ {
+ b.append(d.line);
+ b.append("\n");
+ }
+ textArea.append(b.toString());
+ }
+
+ @Override
+ public void done()
+ {
+ try
+ {
+ StringBuilder result = get();
+ textArea.setText(result.toString());
+ statusLine.setText("Done");
+ }
+ catch (InterruptedException ex)
+ {
+ }
+ catch (CancellationException ex)
+ {
+ textArea.setText("");
+ statusLine.setText("Cancelled");
+ }
+ catch (ExecutionException ex)
+ {
+ statusLine.setText("" + ex.getCause());
+ }
+
+ cancelItem.setEnabled(false);
+ openItem.setEnabled(true);
+ }
+
+ private File file;
+ private StringBuilder text = new StringBuilder();
+ };
+
+ private JFileChooser chooser;
+ private JTextArea textArea;
+ private JLabel statusLine;
+ private JMenuItem openItem;
+ private JMenuItem cancelItem;
+ private SwingWorker textReader;
+
+ public static final int DEFAULT_WIDTH = 450;
+ public static final int DEFAULT_HEIGHT = 350;
+}
\ No newline at end of file
diff --git a/volume1/v1ch14/SynchBankTest/Bank.java b/volume1/v1ch14/SynchBankTest/Bank.java
new file mode 100755
index 0000000..b5cc5ef
--- /dev/null
+++ b/volume1/v1ch14/SynchBankTest/Bank.java
@@ -0,0 +1,86 @@
+package SynchBankTest;
+
+import java.util.concurrent.locks.*;
+
+/**
+ * A bank with a number of bank accounts that uses locks for serializing access.
+ * @version 1.30 2004-08-01
+ * @author Cay Horstmann
+ */
+public class Bank
+{
+ /**
+ * Constructs the bank.
+ * @param n the number of accounts
+ * @param initialBalance the initial balance for each account
+ */
+ public Bank(int n, double initialBalance)
+ {
+ accounts = new double[n];
+ for (int i = 0; i < accounts.length; i++)
+ accounts[i] = initialBalance;
+ bankLock = new ReentrantLock();
+ sufficientFunds = bankLock.newCondition();
+ }
+
+ /**
+ * Transfers money from one account to another.
+ * @param from the account to transfer from
+ * @param to the account to transfer to
+ * @param amount the amount to transfer
+ */
+ public void transfer(int from, int to, double amount) throws InterruptedException
+ {
+ bankLock.lock();
+ try
+ {
+ while (accounts[from] < amount)
+ sufficientFunds.await();
+ System.out.print(Thread.currentThread());
+ accounts[from] -= amount;
+ System.out.printf(" %10.2f from %d to %d", amount, from, to);
+ accounts[to] += amount;
+ System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
+ sufficientFunds.signalAll();
+ }
+ finally
+ {
+ bankLock.unlock();
+ }
+ }
+
+ /**
+ * Gets the sum of all account balances.
+ * @return the total balance
+ */
+ public double getTotalBalance()
+ {
+ bankLock.lock();
+ try
+ {
+ double sum = 0;
+
+ for (double a : accounts)
+ sum += a;
+
+ return sum;
+ }
+ finally
+ {
+ bankLock.unlock();
+ }
+ }
+
+ /**
+ * Gets the number of accounts in the bank.
+ * @return the number of accounts
+ */
+ public int size()
+ {
+ return accounts.length;
+ }
+
+ private final double[] accounts;
+ private Lock bankLock;
+ private Condition sufficientFunds;
+}
diff --git a/volume1/v1ch14/SynchBankTest/SynchBankTest.java b/volume1/v1ch14/SynchBankTest/SynchBankTest.java
new file mode 100755
index 0000000..4625d7e
--- /dev/null
+++ b/volume1/v1ch14/SynchBankTest/SynchBankTest.java
@@ -0,0 +1,25 @@
+package SynchBankTest;
+
+/**
+ * This program shows how multiple threads can safely access a data structure.
+ * @version 1.30 2004-08-01
+ * @author Cay Horstmann
+ */
+public class SynchBankTest
+{
+ public static void main(String[] args)
+ {
+ Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE);
+ int i;
+ for (i = 0; i < NACCOUNTS; i++)
+ {
+ TransferRunnable r = new TransferRunnable(b, i, INITIAL_BALANCE);
+ Thread t = new Thread(r);
+ t.start();
+ }
+ }
+
+ public static final int NACCOUNTS = 100;
+ public static final double INITIAL_BALANCE = 1000;
+}
+
diff --git a/volume1/v1ch14/SynchBankTest/TransferRunnable.java b/volume1/v1ch14/SynchBankTest/TransferRunnable.java
new file mode 100755
index 0000000..26672d9
--- /dev/null
+++ b/volume1/v1ch14/SynchBankTest/TransferRunnable.java
@@ -0,0 +1,44 @@
+package SynchBankTest;
+
+/**
+ * A runnable that transfers money from an account to other accounts in a bank.
+ * @version 1.30 2004-08-01
+ * @author Cay Horstmann
+ */
+public class TransferRunnable implements Runnable
+{
+ /**
+ * Constructs a transfer runnable.
+ * @param b the bank between whose account money is transferred
+ * @param from the account to transfer money from
+ * @param max the maximum amount of money in each transfer
+ */
+ public TransferRunnable(Bank b, int from, double max)
+ {
+ bank = b;
+ fromAccount = from;
+ maxAmount = max;
+ }
+
+ public void run()
+ {
+ try
+ {
+ while (true)
+ {
+ int toAccount = (int) (bank.size() * Math.random());
+ double amount = maxAmount * Math.random();
+ bank.transfer(fromAccount, toAccount, amount);
+ Thread.sleep((int) (DELAY * Math.random()));
+ }
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+
+ private Bank bank;
+ private int fromAccount;
+ private double maxAmount;
+ private int DELAY = 10;
+}
\ No newline at end of file
diff --git a/volume1/v1ch14/SynchBankTest2/Bank.java b/volume1/v1ch14/SynchBankTest2/Bank.java
new file mode 100755
index 0000000..b14e234
--- /dev/null
+++ b/volume1/v1ch14/SynchBankTest2/Bank.java
@@ -0,0 +1,64 @@
+package SynchBankTest2;
+
+/**
+ * A bank with a number of bank accounts that uses synchronization primitives.
+ * @version 1.30 2004-08-01
+ * @author Cay Horstmann
+ */
+public class Bank
+{
+ /**
+ * Constructs the bank.
+ * @param n the number of accounts
+ * @param initialBalance the initial balance for each account
+ */
+ public Bank(int n, double initialBalance)
+ {
+ accounts = new double[n];
+ for (int i = 0; i < accounts.length; i++)
+ accounts[i] = initialBalance;
+ }
+
+ /**
+ * Transfers money from one account to another.
+ * @param from the account to transfer from
+ * @param to the account to transfer to
+ * @param amount the amount to transfer
+ */
+ public synchronized void transfer(int from, int to, double amount) throws InterruptedException
+ {
+ while (accounts[from] < amount)
+ wait();
+ System.out.print(Thread.currentThread());
+ accounts[from] -= amount;
+ System.out.printf(" %10.2f from %d to %d", amount, from, to);
+ accounts[to] += amount;
+ System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
+ notifyAll();
+ }
+
+ /**
+ * Gets the sum of all account balances.
+ * @return the total balance
+ */
+ public synchronized double getTotalBalance()
+ {
+ double sum = 0;
+
+ for (double a : accounts)
+ sum += a;
+
+ return sum;
+ }
+
+ /**
+ * Gets the number of accounts in the bank.
+ * @return the number of accounts
+ */
+ public int size()
+ {
+ return accounts.length;
+ }
+
+ private final double[] accounts;
+}
diff --git a/volume1/v1ch14/SynchBankTest2/SynchBankTest2.java b/volume1/v1ch14/SynchBankTest2/SynchBankTest2.java
new file mode 100755
index 0000000..dde74b8
--- /dev/null
+++ b/volume1/v1ch14/SynchBankTest2/SynchBankTest2.java
@@ -0,0 +1,25 @@
+package SynchBankTest2;
+
+/**
+ * This program shows how multiple threads can safely access a data structure, using synchronized
+ * methods.
+ * @version 1.30 2004-08-01
+ * @author Cay Horstmann
+ */
+public class SynchBankTest2
+{
+ public static void main(String[] args)
+ {
+ Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE);
+ int i;
+ for (i = 0; i < NACCOUNTS; i++)
+ {
+ TransferRunnable r = new TransferRunnable(b, i, INITIAL_BALANCE);
+ Thread t = new Thread(r);
+ t.start();
+ }
+ }
+
+ public static final int NACCOUNTS = 100;
+ public static final double INITIAL_BALANCE = 1000;
+}
diff --git a/volume1/v1ch14/SynchBankTest2/TransferRunnable.java b/volume1/v1ch14/SynchBankTest2/TransferRunnable.java
new file mode 100755
index 0000000..8ccfe65
--- /dev/null
+++ b/volume1/v1ch14/SynchBankTest2/TransferRunnable.java
@@ -0,0 +1,44 @@
+package SynchBankTest2;
+
+/**
+ * A runnable that transfers money from an account to other accounts in a bank.
+ * @version 1.30 2004-08-01
+ * @author Cay Horstmann
+ */
+public class TransferRunnable implements Runnable
+{
+ /**
+ * Constructs a transfer runnable.
+ * @param b the bank between whose account money is transferred
+ * @param from the account to transfer money from
+ * @param max the maximum amount of money in each transfer
+ */
+ public TransferRunnable(Bank b, int from, double max)
+ {
+ bank = b;
+ fromAccount = from;
+ maxAmount = max;
+ }
+
+ public void run()
+ {
+ try
+ {
+ while (true)
+ {
+ int toAccount = (int) (bank.size() * Math.random());
+ double amount = maxAmount * Math.random();
+ bank.transfer(fromAccount, toAccount, amount);
+ Thread.sleep((int) (DELAY * Math.random()));
+ }
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+
+ private Bank bank;
+ private int fromAccount;
+ private double maxAmount;
+ private int DELAY = 10;
+}
\ No newline at end of file
diff --git a/volume1/v1ch14/ThreadPoolTest/ThreadPoolTest.java b/volume1/v1ch14/ThreadPoolTest/ThreadPoolTest.java
new file mode 100755
index 0000000..5ee9e8f
--- /dev/null
+++ b/volume1/v1ch14/ThreadPoolTest/ThreadPoolTest.java
@@ -0,0 +1,127 @@
+package ThreadPoolTest;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+/**
+ * @version 1.0 2004-08-01
+ * @author Cay Horstmann
+ */
+public class ThreadPoolTest
+{
+ public static void main(String[] args) throws Exception
+ {
+ Scanner in = new Scanner(System.in);
+ System.out.print("Enter base directory (e.g. /usr/local/jdk5.0/src): ");
+ String directory = in.nextLine();
+ System.out.print("Enter keyword (e.g. volatile): ");
+ String keyword = in.nextLine();
+
+ ExecutorService pool = Executors.newCachedThreadPool();
+
+ MatchCounter counter = new MatchCounter(new File(directory), keyword, pool);
+ Future result = pool.submit(counter);
+
+ try
+ {
+ System.out.println(result.get() + " matching files.");
+ }
+ catch (ExecutionException e)
+ {
+ e.printStackTrace();
+ }
+ catch (InterruptedException e)
+ {
+ }
+ pool.shutdown();
+
+ int largestPoolSize = ((ThreadPoolExecutor) pool).getLargestPoolSize();
+ System.out.println("largest pool size=" + largestPoolSize);
+ }
+}
+
+/**
+ * This task counts the files in a directory and its subdirectories that contain a given keyword.
+ */
+class MatchCounter implements Callable
+{
+ /**
+ * Constructs a MatchCounter.
+ * @param directory the directory in which to start the search
+ * @param keyword the keyword to look for
+ * @param pool the thread pool for submitting subtasks
+ */
+ public MatchCounter(File directory, String keyword, ExecutorService pool)
+ {
+ this.directory = directory;
+ this.keyword = keyword;
+ this.pool = pool;
+ }
+
+ public Integer call()
+ {
+ count = 0;
+ try
+ {
+ File[] files = directory.listFiles();
+ ArrayList> results = new ArrayList>();
+
+ for (File file : files)
+ if (file.isDirectory())
+ {
+ MatchCounter counter = new MatchCounter(file, keyword, pool);
+ Future result = pool.submit(counter);
+ results.add(result);
+ }
+ else
+ {
+ if (search(file)) count++;
+ }
+
+ for (Future result : results)
+ try
+ {
+ count += result.get();
+ }
+ catch (ExecutionException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ catch (InterruptedException e)
+ {
+ }
+ return count;
+ }
+
+ /**
+ * Searches a file for a given keyword.
+ * @param file the file to search
+ * @return true if the keyword is contained in the file
+ */
+ public boolean search(File file)
+ {
+ try
+ {
+ Scanner in = new Scanner(new FileInputStream(file));
+ boolean found = false;
+ while (!found && in.hasNextLine())
+ {
+ String line = in.nextLine();
+ if (line.contains(keyword)) found = true;
+ }
+ in.close();
+ return found;
+ }
+ catch (IOException e)
+ {
+ return false;
+ }
+ }
+
+ private File directory;
+ private String keyword;
+ private ExecutorService pool;
+ private int count;
+}
diff --git a/volume1/v1ch14/UnsynchBankTest/Bank.java b/volume1/v1ch14/UnsynchBankTest/Bank.java
new file mode 100755
index 0000000..6c46ad4
--- /dev/null
+++ b/volume1/v1ch14/UnsynchBankTest/Bank.java
@@ -0,0 +1,63 @@
+package UnsynchBankTest;
+
+/**
+ * A bank with a number of bank accounts.
+ * @version 1.30 2004-08-01
+ * @author Cay Horstmann
+ */
+public class Bank
+{
+ /**
+ * Constructs the bank.
+ * @param n the number of accounts
+ * @param initialBalance the initial balance for each account
+ */
+ public Bank(int n, double initialBalance)
+ {
+ accounts = new double[n];
+ for (int i = 0; i < accounts.length; i++)
+ accounts[i] = initialBalance;
+ }
+
+ /**
+ * Transfers money from one account to another.
+ * @param from the account to transfer from
+ * @param to the account to transfer to
+ * @param amount the amount to transfer
+ */
+ public void transfer(int from, int to, double amount)
+ {
+ if (accounts[from] < amount) return;
+ System.out.print(Thread.currentThread());
+ accounts[from] -= amount;
+ System.out.printf(" %10.2f from %d to %d", amount, from, to);
+ accounts[to] += amount;
+ System.out.printf(" Total Balance: %10.2f%n", getTotalBalance());
+ }
+
+ /**
+ * Gets the sum of all account balances.
+ * @return the total balance
+ */
+ public double getTotalBalance()
+ {
+ double sum = 0;
+
+ for (double a : accounts)
+ sum += a;
+
+ return sum;
+ }
+
+ /**
+ * Gets the number of accounts in the bank.
+ * @return the number of accounts
+ */
+ public int size()
+ {
+ return accounts.length;
+ }
+
+ private final double[] accounts;
+}
+
diff --git a/volume1/v1ch14/UnsynchBankTest/TransferRunnable.java b/volume1/v1ch14/UnsynchBankTest/TransferRunnable.java
new file mode 100755
index 0000000..f5baa42
--- /dev/null
+++ b/volume1/v1ch14/UnsynchBankTest/TransferRunnable.java
@@ -0,0 +1,44 @@
+package UnsynchBankTest;
+
+/**
+ * A runnable that transfers money from an account to other accounts in a bank.
+ * @version 1.30 2004-08-01
+ * @author Cay Horstmann
+ */
+public class TransferRunnable implements Runnable
+{
+ /**
+ * Constructs a transfer runnable.
+ * @param b the bank between whose account money is transferred
+ * @param from the account to transfer money from
+ * @param max the maximum amount of money in each transfer
+ */
+ public TransferRunnable(Bank b, int from, double max)
+ {
+ bank = b;
+ fromAccount = from;
+ maxAmount = max;
+ }
+
+ public void run()
+ {
+ try
+ {
+ while (true)
+ {
+ int toAccount = (int) (bank.size() * Math.random());
+ double amount = maxAmount * Math.random();
+ bank.transfer(fromAccount, toAccount, amount);
+ Thread.sleep((int) (DELAY * Math.random()));
+ }
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+
+ private Bank bank;
+ private int fromAccount;
+ private double maxAmount;
+ private int DELAY = 10;
+}
\ No newline at end of file
diff --git a/volume1/v1ch14/UnsynchBankTest/UnsynchBankTest.java b/volume1/v1ch14/UnsynchBankTest/UnsynchBankTest.java
new file mode 100755
index 0000000..a01dbd9
--- /dev/null
+++ b/volume1/v1ch14/UnsynchBankTest/UnsynchBankTest.java
@@ -0,0 +1,25 @@
+package UnsynchBankTest;
+
+/**
+ * This program shows data corruption when multiple threads access a data structure.
+ * @version 1.30 2004-08-01
+ * @author Cay Horstmann
+ */
+public class UnsynchBankTest
+{
+ public static void main(String[] args)
+ {
+ Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE);
+ int i;
+ for (i = 0; i < NACCOUNTS; i++)
+ {
+ TransferRunnable r = new TransferRunnable(b, i, INITIAL_BALANCE);
+ Thread t = new Thread(r);
+ t.start();
+ }
+ }
+
+ public static final int NACCOUNTS = 100;
+ public static final double INITIAL_BALANCE = 1000;
+}
+
diff --git a/volume1/v1ch14/v1ch14.iml b/volume1/v1ch14/v1ch14.iml
new file mode 100644
index 0000000..8021953
--- /dev/null
+++ b/volume1/v1ch14/v1ch14.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/volume1/volume1.iml b/volume1/volume1.iml
new file mode 100644
index 0000000..c90834f
--- /dev/null
+++ b/volume1/volume1.iml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/volume2/v2ch01/FindDirectories/FindDirectories.iml b/volume2/v2ch01/FindDirectories/FindDirectories.iml
new file mode 100644
index 0000000..6e2c775
--- /dev/null
+++ b/volume2/v2ch01/FindDirectories/FindDirectories.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/volume2/v2ch01/HrefMatch/HrefMatch.iml b/volume2/v2ch01/HrefMatch/HrefMatch.iml
new file mode 100644
index 0000000..6e2c775
--- /dev/null
+++ b/volume2/v2ch01/HrefMatch/HrefMatch.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/volume2/v2ch01/v2ch01.iml b/volume2/v2ch01/v2ch01.iml
new file mode 100644
index 0000000..d6ebd48
--- /dev/null
+++ b/volume2/v2ch01/v2ch01.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/volume2/v2ch02/v2ch02.iml b/volume2/v2ch02/v2ch02.iml
new file mode 100644
index 0000000..0ea175e
--- /dev/null
+++ b/volume2/v2ch02/v2ch02.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/volume2/v2ch03/v2ch03.iml b/volume2/v2ch03/v2ch03.iml
new file mode 100644
index 0000000..6af6c40
--- /dev/null
+++ b/volume2/v2ch03/v2ch03.iml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/volume2/volume2.iml b/volume2/volume2.iml
new file mode 100644
index 0000000..c90834f
--- /dev/null
+++ b/volume2/volume2.iml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file