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