diff --git a/javacore第11版/corejava/gutenberg/alice30.txt b/corejava第10版/gutenberg/alice30.txt
similarity index 100%
rename from javacore第11版/corejava/gutenberg/alice30.txt
rename to corejava第10版/gutenberg/alice30.txt
diff --git a/javacore第11版/corejava/gutenberg/crsto10.txt b/corejava第10版/gutenberg/crsto10.txt
similarity index 100%
rename from javacore第11版/corejava/gutenberg/crsto10.txt
rename to corejava第10版/gutenberg/crsto10.txt
diff --git a/corejava第10版/v1ch02/ImageViewer/ImageViewer.java b/corejava第10版/v1ch02/ImageViewer/ImageViewer.java
new file mode 100644
index 0000000..0e6f862
--- /dev/null
+++ b/corejava第10版/v1ch02/ImageViewer/ImageViewer.java
@@ -0,0 +1,70 @@
+import java.awt.*;
+import java.io.*;
+import javax.swing.*;
+
+/**
+ * A program for viewing images.
+ * @version 1.30 2014-02-27
+ * @author Cay Horstmann
+ */
+public class ImageViewer
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new ImageViewerFrame();
+ frame.setTitle("ImageViewer");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * A frame with a label to show an image.
+ */
+class ImageViewerFrame extends JFrame
+{
+ private JLabel label;
+ private JFileChooser chooser;
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 400;
+
+ public ImageViewerFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ // use a label to display the images
+ label = new JLabel();
+ add(label);
+
+ // set up the file chooser
+ chooser = new JFileChooser();
+ chooser.setCurrentDirectory(new File("."));
+
+ // set up the menu bar
+ JMenuBar menuBar = new JMenuBar();
+ setJMenuBar(menuBar);
+
+ JMenu menu = new JMenu("File");
+ menuBar.add(menu);
+
+ JMenuItem openItem = new JMenuItem("Open");
+ menu.add(openItem);
+ openItem.addActionListener(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)
+ {
+ String name = chooser.getSelectedFile().getPath();
+ label.setIcon(new ImageIcon(name));
+ }
+ });
+
+ JMenuItem exitItem = new JMenuItem("Exit");
+ menu.add(exitItem);
+ exitItem.addActionListener(event -> System.exit(0));
+ }
+}
diff --git a/javacore第11版/corejava/v1ch02/FXImageViewer/cay.jpg b/corejava第10版/v1ch02/ImageViewer/cay.jpg
similarity index 100%
rename from javacore第11版/corejava/v1ch02/FXImageViewer/cay.jpg
rename to corejava第10版/v1ch02/ImageViewer/cay.jpg
diff --git a/javacore第11版/corejava/v1ch02/FXImageViewer/duke.gif b/corejava第10版/v1ch02/ImageViewer/duke.gif
similarity index 100%
rename from javacore第11版/corejava/v1ch02/FXImageViewer/duke.gif
rename to corejava第10版/v1ch02/ImageViewer/duke.gif
diff --git a/javacore第11版/corejava/v1ch02/ImageViewer/cup.png b/corejava第10版/v1ch02/ImageViewer/mug.png
similarity index 100%
rename from javacore第11版/corejava/v1ch02/ImageViewer/cup.png
rename to corejava第10版/v1ch02/ImageViewer/mug.png
diff --git a/corejava第10版/v1ch02/RoadApplet/RoadApplet.html b/corejava第10版/v1ch02/RoadApplet/RoadApplet.html
new file mode 100644
index 0000000..784697a
--- /dev/null
+++ b/corejava第10版/v1ch02/RoadApplet/RoadApplet.html
@@ -0,0 +1,60 @@
+
+
A Traffic Simulator Applet
+
+ Traffic Simulator Applet
+
+ I wrote this traffic simulation, following the article "Und nun die
+ Stauvorhersage" of the German Magazine Die Zeit , June 7,
+ 1996. The article describes the work of Professor Michael Schreckenberger
+ of the University of Duisburg and unnamed collaborators at the University
+ of Cologne and Los Alamos National Laboratory. These researchers model
+ traffic flow according to simple rules, such as the following:
+
+ A freeway is modeled as a sequence of grid points.
+ Every car occupies one grid point. Each grid point occupies at most
+ one car.
+ A car can have a speed of 0 - 5 grid points per time interval.
+ A car with speed of less than 5 increases its speed by one unit in
+ each time interval, until it reaches the maximum speed.
+ If a car's distance to the car in front is d grid points, its
+ speed is reduced to d -1 if necessary to avoid crashing into it.
+
+ With a certain probability, in each time interval some cars slow down
+ one unit for no good reason whatsoever.
+
+
+ This applet models these rules. Each line shows an image of the same
+ stretch of road. Each square denotes one car. The first scrollbar lets you
+ adjust the probability that some cars slow down. If the slider is all the
+ way to the left, no car slows down. If it is all the way to the right,
+ every car slows down one unit. A typical setting is that 10% - 20% of the
+ cars slow down. The second slider controls the arrival rate of the cars.
+ When it is all the way to the left, no new cars enter the freeway. If it
+ is all the way to the right, a new car enters the freeway every time
+ interval, provided the freeway entrance is not blocked.
+
+ Try out the following experiments. Decrease the probability of slowdown
+ to 0. Crank up the arrival rate to 1. That means, every time unit, a new
+ car enters the road. Note how the road can carry this load.
+
+ Now increase the probability that some cars slow down. Note how traffic
+ jams occur almost immediately.
+
+ The moral is: If it wasn't for the rubberneckers, the cellular phone
+ users, and the makeup-appliers who can't keep up a constant speed, we'd all
+ get to work more quickly.
+
+ Notice how the traffic jam is stationary or even moves backwards, even
+ though the individual cars are still moving. In fact, the first car
+ causing the jam has long left the scene by the time the jam gets bad.
+ (To make it easier to track cars, every tenth vehicle is colored red.)
+
+
+
+
+ For more information about applets, graphics programming and
+ multithreading in Java, see
+ Core Java .
+
+
diff --git a/corejava第10版/v1ch02/RoadApplet/RoadApplet.jar b/corejava第10版/v1ch02/RoadApplet/RoadApplet.jar
new file mode 100644
index 0000000..120bd33
Binary files /dev/null and b/corejava第10版/v1ch02/RoadApplet/RoadApplet.jar differ
diff --git a/corejava第10版/v1ch02/RoadApplet/RoadApplet.java b/corejava第10版/v1ch02/RoadApplet/RoadApplet.java
new file mode 100644
index 0000000..6affcf8
--- /dev/null
+++ b/corejava第10版/v1ch02/RoadApplet/RoadApplet.java
@@ -0,0 +1,46 @@
+import java.awt.*;
+import java.applet.*;
+import javax.swing.*;
+
+public class RoadApplet extends JApplet
+{
+ private RoadComponent roadComponent;
+ private JSlider slowdown;
+ private JSlider arrival;
+
+ public void init()
+ {
+ EventQueue.invokeLater(() ->
+ {
+ roadComponent = new RoadComponent();
+ slowdown = new JSlider(0, 100, 10);
+ arrival = new JSlider(0, 100, 50);
+
+ JPanel p = new JPanel();
+ p.setLayout(new GridLayout(1, 6));
+ p.add(new JLabel("Slowdown"));
+ p.add(slowdown);
+ p.add(new JLabel(""));
+ p.add(new JLabel("Arrival"));
+ p.add(arrival);
+ p.add(new JLabel(""));
+ setLayout(new BorderLayout());
+ add(p, BorderLayout.NORTH);
+ add(roadComponent, BorderLayout.CENTER);
+ });
+ }
+
+ public void start()
+ {
+ new Thread(() ->
+ {
+ for (;;)
+ {
+ roadComponent.update(
+ 0.01 * slowdown.getValue(),
+ 0.01 * arrival.getValue());
+ try { Thread.sleep(50); } catch(InterruptedException e) {}
+ }
+ }).start();
+ }
+}
diff --git a/corejava第10版/v1ch02/RoadApplet/RoadApplet.mf b/corejava第10版/v1ch02/RoadApplet/RoadApplet.mf
new file mode 100644
index 0000000..f978ab7
--- /dev/null
+++ b/corejava第10版/v1ch02/RoadApplet/RoadApplet.mf
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+Permissions: sandbox
diff --git a/corejava第10版/v1ch02/RoadApplet/RoadComponent.java b/corejava第10版/v1ch02/RoadApplet/RoadComponent.java
new file mode 100644
index 0000000..2aecc34
--- /dev/null
+++ b/corejava第10版/v1ch02/RoadApplet/RoadComponent.java
@@ -0,0 +1,123 @@
+import java.awt.*;
+import java.awt.image.*;
+import javax.swing.*;
+
+public class RoadComponent extends JComponent
+{
+ private final int DOTSIZE = 2;
+ private final int XDOTDIST = 1;
+ private Road freeway;
+ private BufferedImage buffer;
+ private int row;
+ private int xsize;
+ private int ysize;
+
+ public RoadComponent()
+ {
+ freeway = new Road();
+ row = 0;
+ }
+
+ public void update(double slowdown, double arrival)
+ {
+ freeway.update(slowdown, arrival);
+ Graphics g;
+ if (buffer == null)
+ {
+ xsize = getWidth();
+ ysize = getHeight();
+ if (xsize == 0 || ysize == 0) return;
+ buffer = new BufferedImage(xsize, ysize, BufferedImage.TYPE_INT_ARGB);
+ g = buffer.getGraphics();
+ g.setColor(Color.WHITE);
+ g.fillRect(0, 0, xsize, ysize);
+ }
+ else
+ g = buffer.getGraphics();
+
+ if (row < ysize - 2 * DOTSIZE)
+ row += DOTSIZE;
+ else
+ {
+ g.copyArea(0, DOTSIZE, xsize, ysize - DOTSIZE, 0, -DOTSIZE);
+ }
+ freeway.paint(g, row, XDOTDIST, DOTSIZE);
+ g.dispose();
+ repaint();
+ }
+
+ public void paintComponent(Graphics g)
+ {
+ if (buffer != null)
+ g.drawImage(buffer, 0, 0, null);
+ }
+}
+
+class Road
+{
+ public static final int LENGTH = 400;
+ public static final int MAXSPEED = 5;
+
+ private int[] speed;
+ private Color[] colors;
+ private int count;
+
+ public Road()
+ {
+ speed = new int[LENGTH];
+ colors = new Color[LENGTH];
+ for (int i = 0; i < LENGTH; i++) speed[i] = -1;
+ }
+
+ public void update(double prob_slowdown, double prob_create)
+ {
+ int i = 0;
+ while(i < LENGTH && speed[i] == -1)
+ i++;
+ while (i < LENGTH)
+ {
+ if (Math.random() <= prob_slowdown && speed[i] > 0)
+ speed[i]--;
+ else if (speed[i] < MAXSPEED)
+ speed[i]++;
+ int inext = i + 1;
+ while(inext < LENGTH && speed[inext] == -1)
+ inext++;
+ if (inext < LENGTH)
+ {
+ if (speed[i] >= inext - i)
+ speed[i] = inext - i - 1;
+ }
+ if (speed[i] > 0)
+ {
+ if (i + speed[i] < LENGTH)
+ {
+ int ni = i + speed[i];
+ speed[ni] = speed[i];
+ colors[ni] = colors[i];
+ }
+ speed[i] = -1;
+ }
+ i = inext;
+ }
+ if (Math.random() <= prob_create && speed[0] == -1)
+ {
+ speed[0] = (int)(5.99 * Math.random());
+ colors[0] = ++count % 10 == 0 ? Color.red : Color.black;
+ }
+ }
+
+ public void paint(Graphics g, int row, int dotdist, int dotsize)
+ {
+ g.setColor(Color.WHITE);
+ g.fillRect(0, row, LENGTH * dotsize, dotsize);
+ for (int i = 0; i < LENGTH; i++)
+ {
+ if (speed[i] >= 0)
+ {
+ g.setColor(colors[i]);
+ g.fillRect(i * dotdist, row, dotsize, dotsize);
+ }
+ }
+ }
+}
diff --git a/corejava第10版/v1ch02/RoadApplet/makejar b/corejava第10版/v1ch02/RoadApplet/makejar
new file mode 100644
index 0000000..eaf47f2
--- /dev/null
+++ b/corejava第10版/v1ch02/RoadApplet/makejar
@@ -0,0 +1,3 @@
+javac RoadApplet.java
+jar cvfm RoadApplet.jar RoadApplet.mf *.class
+rm *.class
diff --git a/javacore第11版/corejava/v1ch02/Welcome/Welcome.java b/corejava第10版/v1ch02/Welcome/Welcome.java
similarity index 100%
rename from javacore第11版/corejava/v1ch02/Welcome/Welcome.java
rename to corejava第10版/v1ch02/Welcome/Welcome.java
diff --git a/corejava第10版/v1ch03/BigIntegerTest/BigIntegerTest.java b/corejava第10版/v1ch03/BigIntegerTest/BigIntegerTest.java
new file mode 100644
index 0000000..ca72a4a
--- /dev/null
+++ b/corejava第10版/v1ch03/BigIntegerTest/BigIntegerTest.java
@@ -0,0 +1,33 @@
+import java.math.*;
+import java.util.*;
+
+/**
+ * This program uses big numbers to compute the odds of winning the grand prize in a lottery.
+ * @version 1.20 2004-02-10
+ * @author Cay Horstmann
+ */
+public class BigIntegerTest
+{
+ public static void main(String[] args)
+ {
+ Scanner in = new Scanner(System.in);
+
+ System.out.print("How many numbers do you need to draw? ");
+ int k = in.nextInt();
+
+ System.out.print("What is the highest number you can draw? ");
+ int n = in.nextInt();
+
+ /*
+ * compute binomial coefficient n*(n-1)*(n-2)*...*(n-k+1)/(1*2*3*...*k)
+ */
+
+ BigInteger lotteryOdds = BigInteger.valueOf(1);
+
+ for (int i = 1; i <= k; i++)
+ lotteryOdds = lotteryOdds.multiply(BigInteger.valueOf(n - i + 1)).divide(
+ BigInteger.valueOf(i));
+
+ System.out.println("Your odds are 1 in " + lotteryOdds + ". Good luck!");
+ }
+}
diff --git a/javacore第11版/corejava/v1ch03/CompoundInterest/CompoundInterest.java b/corejava第10版/v1ch03/CompoundInterest/CompoundInterest.java
similarity index 100%
rename from javacore第11版/corejava/v1ch03/CompoundInterest/CompoundInterest.java
rename to corejava第10版/v1ch03/CompoundInterest/CompoundInterest.java
diff --git a/javacore第11版/corejava/v1ch03/FirstSample/FirstSample.java b/corejava第10版/v1ch03/FirstSample/FirstSample.java
similarity index 100%
rename from javacore第11版/corejava/v1ch03/FirstSample/FirstSample.java
rename to corejava第10版/v1ch03/FirstSample/FirstSample.java
diff --git a/javacore第11版/corejava/v1ch03/InputTest/InputTest.java b/corejava第10版/v1ch03/InputTest/InputTest.java
similarity index 100%
rename from javacore第11版/corejava/v1ch03/InputTest/InputTest.java
rename to corejava第10版/v1ch03/InputTest/InputTest.java
diff --git a/javacore第11版/corejava/v1ch03/LotteryArray/LotteryArray.java b/corejava第10版/v1ch03/LotteryArray/LotteryArray.java
similarity index 100%
rename from javacore第11版/corejava/v1ch03/LotteryArray/LotteryArray.java
rename to corejava第10版/v1ch03/LotteryArray/LotteryArray.java
diff --git a/javacore第11版/corejava/v1ch03/LotteryDrawing/LotteryDrawing.java b/corejava第10版/v1ch03/LotteryDrawing/LotteryDrawing.java
similarity index 100%
rename from javacore第11版/corejava/v1ch03/LotteryDrawing/LotteryDrawing.java
rename to corejava第10版/v1ch03/LotteryDrawing/LotteryDrawing.java
diff --git a/javacore第11版/corejava/v1ch03/LotteryOdds/LotteryOdds.java b/corejava第10版/v1ch03/LotteryOdds/LotteryOdds.java
similarity index 100%
rename from javacore第11版/corejava/v1ch03/LotteryOdds/LotteryOdds.java
rename to corejava第10版/v1ch03/LotteryOdds/LotteryOdds.java
diff --git a/javacore第11版/corejava/v1ch03/Retirement/Retirement.java b/corejava第10版/v1ch03/Retirement/Retirement.java
similarity index 100%
rename from javacore第11版/corejava/v1ch03/Retirement/Retirement.java
rename to corejava第10版/v1ch03/Retirement/Retirement.java
diff --git a/javacore第11版/corejava/v1ch03/Retirement2/Retirement2.java b/corejava第10版/v1ch03/Retirement2/Retirement2.java
similarity index 100%
rename from javacore第11版/corejava/v1ch03/Retirement2/Retirement2.java
rename to corejava第10版/v1ch03/Retirement2/Retirement2.java
diff --git a/corejava第10版/v1ch04/CalendarTest/CalendarTest.java b/corejava第10版/v1ch04/CalendarTest/CalendarTest.java
new file mode 100644
index 0000000..821c429
--- /dev/null
+++ b/corejava第10版/v1ch04/CalendarTest/CalendarTest.java
@@ -0,0 +1,35 @@
+import java.time.*;
+
+/**
+ * @version 1.5 2015-05-08
+ * @author Cay Horstmann
+ */
+
+public class CalendarTest
+{
+ public static void main(String[] args)
+ {
+ LocalDate date = LocalDate.now();
+ int month = date.getMonthValue();
+ int today = date.getDayOfMonth();
+
+ date = date.minusDays(today - 1); // Set to start of month
+ DayOfWeek weekday = date.getDayOfWeek();
+ int value = weekday.getValue(); // 1 = Monday, ... 7 = Sunday
+
+ System.out.println("Mon Tue Wed Thu Fri Sat Sun");
+ for (int i = 1; i < value; i++)
+ System.out.print(" ");
+ while (date.getMonthValue() == month)
+ {
+ System.out.printf("%3d", date.getDayOfMonth());
+ if (date.getDayOfMonth() == today)
+ System.out.print("*");
+ else
+ System.out.print(" ");
+ date = date.plusDays(1);
+ if (date.getDayOfWeek().getValue() == 1) System.out.println();
+ }
+ if (date.getDayOfWeek().getValue() != 1) System.out.println();
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch04/ConstructorTest/ConstructorTest.java b/corejava第10版/v1ch04/ConstructorTest/ConstructorTest.java
new file mode 100644
index 0000000..d515e45
--- /dev/null
+++ b/corejava第10版/v1ch04/ConstructorTest/ConstructorTest.java
@@ -0,0 +1,83 @@
+import java.util.*;
+
+/**
+ * This program demonstrates object construction.
+ * @version 1.01 2004-02-19
+ * @author Cay Horstmann
+ */
+public class ConstructorTest
+{
+ public static void main(String[] args)
+ {
+ // fill the staff array with three Employee objects
+ Employee[] staff = new Employee[3];
+
+ staff[0] = new Employee("Harry", 40000);
+ staff[1] = new Employee(60000);
+ staff[2] = new Employee();
+
+ // print out information about all Employee objects
+ for (Employee e : staff)
+ System.out.println("name=" + e.getName() + ",id=" + e.getId() + ",salary="
+ + e.getSalary());
+ }
+}
+
+class Employee
+{
+ private static int nextId;
+
+ private int id;
+ private String name = ""; // instance field initialization
+ private double salary;
+
+ // static initialization block
+ static
+ {
+ Random generator = new Random();
+ // set nextId to a random number between 0 and 9999
+ nextId = generator.nextInt(10000);
+ }
+
+ // object initialization block
+ {
+ id = nextId;
+ nextId++;
+ }
+
+ // three overloaded constructors
+ public Employee(String n, double s)
+ {
+ name = n;
+ salary = s;
+ }
+
+ public Employee(double s)
+ {
+ // calls the Employee(String, double) constructor
+ this("Employee #" + nextId, s);
+ }
+
+ // the default constructor
+ public Employee()
+ {
+ // name initialized to ""--see above
+ // salary not explicitly set--initialized to 0
+ // id initialized in initialization block
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public double getSalary()
+ {
+ return salary;
+ }
+
+ public int getId()
+ {
+ return id;
+ }
+}
diff --git a/corejava第10版/v1ch04/EmployeeTest/EmployeeTest.java b/corejava第10版/v1ch04/EmployeeTest/EmployeeTest.java
new file mode 100644
index 0000000..75a8a89
--- /dev/null
+++ b/corejava第10版/v1ch04/EmployeeTest/EmployeeTest.java
@@ -0,0 +1,63 @@
+import java.time.*;
+
+/**
+ * This program tests the Employee class.
+ * @version 1.12 2015-05-08
+ * @author Cay Horstmann
+ */
+public class EmployeeTest
+{
+ public static void main(String[] args)
+ {
+ // fill the staff array with three Employee objects
+ Employee[] staff = new Employee[3];
+
+ staff[0] = new Employee("Carl Cracker", 75000, 1987, 12, 15);
+ staff[1] = new Employee("Harry Hacker", 50000, 1989, 10, 1);
+ staff[2] = new Employee("Tony Tester", 40000, 1990, 3, 15);
+
+ // raise everyone's salary by 5%
+ for (Employee e : staff)
+ e.raiseSalary(5);
+
+ // print out information about all Employee objects
+ for (Employee e : staff)
+ System.out.println("name=" + e.getName() + ",salary=" + e.getSalary() + ",hireDay="
+ + e.getHireDay());
+ }
+}
+
+class Employee
+{
+ private String name;
+ private double salary;
+ private LocalDate hireDay;
+
+ public Employee(String n, double s, int year, int month, int day)
+ {
+ name = n;
+ salary = s;
+ hireDay = LocalDate.of(year, month, day);
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public double getSalary()
+ {
+ return salary;
+ }
+
+ public LocalDate getHireDay()
+ {
+ return hireDay;
+ }
+
+ public void raiseSalary(double byPercent)
+ {
+ double raise = salary * byPercent / 100;
+ salary += raise;
+ }
+}
diff --git a/corejava第10版/v1ch04/PackageTest/PackageTest.java b/corejava第10版/v1ch04/PackageTest/PackageTest.java
new file mode 100644
index 0000000..0b7af00
--- /dev/null
+++ b/corejava第10版/v1ch04/PackageTest/PackageTest.java
@@ -0,0 +1,24 @@
+import com.horstmann.corejava.*;
+// the Employee class is defined in that package
+
+import static java.lang.System.*;
+
+/**
+ * This program demonstrates the use of packages.
+ * @version 1.11 2004-02-19
+ * @author Cay Horstmann
+ */
+public class PackageTest
+{
+ public static void main(String[] args)
+ {
+ // because of the import statement, we don't have to use
+ // com.horstmann.corejava.Employee here
+ Employee harry = new Employee("Harry Hacker", 50000, 1989, 10, 1);
+
+ harry.raiseSalary(5);
+
+ // because of the static import statement, we don't have to use System.out here
+ out.println("name=" + harry.getName() + ",salary=" + harry.getSalary());
+ }
+}
diff --git a/javacore第11版/corejava/v1ch04/PackageTest/com/horstmann/corejava/Employee.java b/corejava第10版/v1ch04/PackageTest/com/horstmann/corejava/Employee.java
similarity index 100%
rename from javacore第11版/corejava/v1ch04/PackageTest/com/horstmann/corejava/Employee.java
rename to corejava第10版/v1ch04/PackageTest/com/horstmann/corejava/Employee.java
diff --git a/corejava第10版/v1ch04/ParamTest/ParamTest.java b/corejava第10版/v1ch04/ParamTest/ParamTest.java
new file mode 100644
index 0000000..30488ed
--- /dev/null
+++ b/corejava第10版/v1ch04/ParamTest/ParamTest.java
@@ -0,0 +1,89 @@
+/**
+ * This program demonstrates parameter passing in Java.
+ * @version 1.00 2000-01-27
+ * @author Cay Horstmann
+ */
+public class ParamTest
+{
+ public static void main(String[] args)
+ {
+ /*
+ * Test 1: Methods can't modify numeric parameters
+ */
+ System.out.println("Testing tripleValue:");
+ double percent = 10;
+ System.out.println("Before: percent=" + percent);
+ tripleValue(percent);
+ System.out.println("After: percent=" + percent);
+
+ /*
+ * Test 2: Methods can change the state of object parameters
+ */
+ System.out.println("\nTesting tripleSalary:");
+ Employee harry = new Employee("Harry", 50000);
+ System.out.println("Before: salary=" + harry.getSalary());
+ tripleSalary(harry);
+ System.out.println("After: salary=" + harry.getSalary());
+
+ /*
+ * Test 3: Methods can't attach new objects to object parameters
+ */
+ System.out.println("\nTesting swap:");
+ Employee a = new Employee("Alice", 70000);
+ Employee b = new Employee("Bob", 60000);
+ System.out.println("Before: a=" + a.getName());
+ System.out.println("Before: b=" + b.getName());
+ swap(a, b);
+ System.out.println("After: a=" + a.getName());
+ System.out.println("After: b=" + b.getName());
+ }
+
+ public static void tripleValue(double x) // doesn't work
+ {
+ x = 3 * x;
+ System.out.println("End of method: x=" + x);
+ }
+
+ public static void tripleSalary(Employee x) // works
+ {
+ x.raiseSalary(200);
+ System.out.println("End of method: salary=" + x.getSalary());
+ }
+
+ public static void swap(Employee x, Employee y)
+ {
+ Employee temp = x;
+ x = y;
+ y = temp;
+ System.out.println("End of method: x=" + x.getName());
+ System.out.println("End of method: y=" + y.getName());
+ }
+}
+
+class Employee // simplified Employee class
+{
+ private String name;
+ private double salary;
+
+ 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;
+ }
+}
diff --git a/corejava第10版/v1ch04/StaticTest/StaticTest.java b/corejava第10版/v1ch04/StaticTest/StaticTest.java
new file mode 100644
index 0000000..d1fd3f6
--- /dev/null
+++ b/corejava第10版/v1ch04/StaticTest/StaticTest.java
@@ -0,0 +1,76 @@
+/**
+ * This program demonstrates static methods.
+ * @version 1.01 2004-02-19
+ * @author Cay Horstmann
+ */
+public class StaticTest
+{
+ public static void main(String[] args)
+ {
+ // fill the staff array with three Employee objects
+ Employee[] staff = new Employee[3];
+
+ staff[0] = new Employee("Tom", 40000);
+ staff[1] = new Employee("Dick", 60000);
+ staff[2] = new Employee("Harry", 65000);
+
+ // print out information about all Employee objects
+ for (Employee e : staff)
+ {
+ e.setId();
+ System.out.println("name=" + e.getName() + ",id=" + e.getId() + ",salary="
+ + e.getSalary());
+ }
+
+ int n = Employee.getNextId(); // calls static method
+ System.out.println("Next available id=" + n);
+ }
+}
+
+class Employee
+{
+ private static int nextId = 1;
+
+ private String name;
+ private double salary;
+ private int id;
+
+ public Employee(String n, double s)
+ {
+ name = n;
+ salary = s;
+ id = 0;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public double getSalary()
+ {
+ return salary;
+ }
+
+ public int getId()
+ {
+ return id;
+ }
+
+ public void setId()
+ {
+ id = nextId; // set id to next available id
+ nextId++;
+ }
+
+ public static int getNextId()
+ {
+ return nextId; // returns static field
+ }
+
+ public static void main(String[] args) // unit test
+ {
+ Employee e = new Employee("Harry", 50000);
+ System.out.println(e.getName() + " " + e.getSalary());
+ }
+}
diff --git a/javacore第11版/corejava/v1ch05/abstractClasses/Employee.java b/corejava第10版/v1ch05/abstractClasses/Employee.java
similarity index 100%
rename from javacore第11版/corejava/v1ch05/abstractClasses/Employee.java
rename to corejava第10版/v1ch05/abstractClasses/Employee.java
diff --git a/javacore第11版/corejava/v1ch05/abstractClasses/Person.java b/corejava第10版/v1ch05/abstractClasses/Person.java
similarity index 100%
rename from javacore第11版/corejava/v1ch05/abstractClasses/Person.java
rename to corejava第10版/v1ch05/abstractClasses/Person.java
diff --git a/corejava第10版/v1ch05/abstractClasses/PersonTest.java b/corejava第10版/v1ch05/abstractClasses/PersonTest.java
new file mode 100644
index 0000000..67733f0
--- /dev/null
+++ b/corejava第10版/v1ch05/abstractClasses/PersonTest.java
@@ -0,0 +1,22 @@
+package abstractClasses;
+
+/**
+ * This program demonstrates abstract classes.
+ * @version 1.01 2004-02-21
+ * @author Cay Horstmann
+ */
+public class PersonTest
+{
+ public static void main(String[] args)
+ {
+ Person[] people = new Person[2];
+
+ // fill the people array with Student and Employee objects
+ people[0] = new Employee("Harry Hacker", 50000, 1989, 10, 1);
+ people[1] = new Student("Maria Morris", "computer science");
+
+ // print out names and descriptions of all Person objects
+ for (Person p : people)
+ System.out.println(p.getName() + ", " + p.getDescription());
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch05/abstractClasses/Student.java b/corejava第10版/v1ch05/abstractClasses/Student.java
new file mode 100644
index 0000000..ae43ce9
--- /dev/null
+++ b/corejava第10版/v1ch05/abstractClasses/Student.java
@@ -0,0 +1,22 @@
+package abstractClasses;
+
+public class Student extends Person
+{
+ private String major;
+
+ /**
+ * @param nama the student's name
+ * @param major the student's major
+ */
+ public Student(String name, String major)
+ {
+ // pass n to superclass constructor
+ super(name);
+ this.major = major;
+ }
+
+ public String getDescription()
+ {
+ return "a student majoring in " + major;
+ }
+}
diff --git a/corejava第10版/v1ch05/arrayList/ArrayListTest.java b/corejava第10版/v1ch05/arrayList/ArrayListTest.java
new file mode 100644
index 0000000..31484b1
--- /dev/null
+++ b/corejava第10版/v1ch05/arrayList/ArrayListTest.java
@@ -0,0 +1,30 @@
+package arrayList;
+
+import java.util.*;
+
+/**
+ * This program demonstrates the ArrayList class.
+ * @version 1.11 2012-01-26
+ * @author Cay Horstmann
+ */
+public class ArrayListTest
+{
+ public static void main(String[] args)
+ {
+ // fill the staff array list with three Employee objects
+ ArrayList staff = new ArrayList<>();
+
+ staff.add(new Employee("Carl Cracker", 75000, 1987, 12, 15));
+ staff.add(new Employee("Harry Hacker", 50000, 1989, 10, 1));
+ staff.add(new Employee("Tony Tester", 40000, 1990, 3, 15));
+
+ // raise everyone's salary by 5%
+ for (Employee e : staff)
+ e.raiseSalary(5);
+
+ // print out information about all Employee objects
+ for (Employee e : staff)
+ System.out.println("name=" + e.getName() + ",salary=" + e.getSalary() + ",hireDay="
+ + e.getHireDay());
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v1ch05/arrayList/Employee.java b/corejava第10版/v1ch05/arrayList/Employee.java
similarity index 100%
rename from javacore第11版/corejava/v1ch05/arrayList/Employee.java
rename to corejava第10版/v1ch05/arrayList/Employee.java
diff --git a/corejava第10版/v1ch05/arrays/CopyOfTest.java b/corejava第10版/v1ch05/arrays/CopyOfTest.java
new file mode 100644
index 0000000..afbd445
--- /dev/null
+++ b/corejava第10版/v1ch05/arrays/CopyOfTest.java
@@ -0,0 +1,58 @@
+package arrays;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+/**
+ * This program demonstrates the use of reflection for manipulating arrays.
+ * @version 1.2 2012-05-04
+ * @author Cay Horstmann
+ */
+public class CopyOfTest
+{
+ public static void main(String[] args)
+ {
+ int[] a = { 1, 2, 3 };
+ a = (int[]) goodCopyOf(a, 10);
+ System.out.println(Arrays.toString(a));
+
+ String[] b = { "Tom", "Dick", "Harry" };
+ b = (String[]) goodCopyOf(b, 10);
+ System.out.println(Arrays.toString(b));
+
+ System.out.println("The following call will generate an exception.");
+ b = (String[]) badCopyOf(b, 10);
+ }
+
+ /**
+ * This method attempts to grow an array by allocating a new array and copying all elements.
+ * @param a the array to grow
+ * @param newLength the new length
+ * @return a larger array that contains all elements of a. However, the returned array has
+ * type Object[], not the same type as a
+ */
+ public static Object[] badCopyOf(Object[] a, int newLength) // not useful
+ {
+ Object[] newArray = new Object[newLength];
+ System.arraycopy(a, 0, newArray, 0, Math.min(a.length, newLength));
+ return newArray;
+ }
+
+ /**
+ * This method grows an array by allocating a new array of the same type and
+ * copying all elements.
+ * @param a the array to grow. This can be an object array or a primitive
+ * type array
+ * @return a larger array that contains all elements of a.
+ */
+ public static Object goodCopyOf(Object a, int newLength)
+ {
+ Class cl = a.getClass();
+ if (!cl.isArray()) return null;
+ Class componentType = cl.getComponentType();
+ int length = Array.getLength(a);
+ Object newArray = Array.newInstance(componentType, newLength);
+ System.arraycopy(a, 0, newArray, 0, Math.min(length, newLength));
+ return newArray;
+ }
+}
diff --git a/corejava第10版/v1ch05/enums/EnumTest.java b/corejava第10版/v1ch05/enums/EnumTest.java
new file mode 100644
index 0000000..180fc25
--- /dev/null
+++ b/corejava第10版/v1ch05/enums/EnumTest.java
@@ -0,0 +1,33 @@
+package enums;
+
+import java.util.*;
+
+/**
+ * This program demonstrates enumerated types.
+ * @version 1.0 2004-05-24
+ * @author Cay Horstmann
+ */
+public class EnumTest
+{
+ public static void main(String[] args)
+ {
+ Scanner in = new Scanner(System.in);
+ System.out.print("Enter a size: (SMALL, MEDIUM, LARGE, EXTRA_LARGE) ");
+ String input = in.next().toUpperCase();
+ Size size = Enum.valueOf(Size.class, input);
+ System.out.println("size=" + size);
+ System.out.println("abbreviation=" + size.getAbbreviation());
+ if (size == Size.EXTRA_LARGE)
+ System.out.println("Good job--you paid attention to the _.");
+ }
+}
+
+enum Size
+{
+ SMALL("S"), MEDIUM("M"), LARGE("L"), EXTRA_LARGE("XL");
+
+ private Size(String abbreviation) { this.abbreviation = abbreviation; }
+ public String getAbbreviation() { return abbreviation; }
+
+ private String abbreviation;
+}
diff --git a/corejava第10版/v1ch05/equals/Employee.java b/corejava第10版/v1ch05/equals/Employee.java
new file mode 100644
index 0000000..66a037f
--- /dev/null
+++ b/corejava第10版/v1ch05/equals/Employee.java
@@ -0,0 +1,68 @@
+package equals;
+
+import java.time.*;
+import java.util.Objects;
+
+public class Employee
+{
+ private String name;
+ private double salary;
+ private LocalDate hireDay;
+
+ public Employee(String name, double salary, int year, int month, int day)
+ {
+ this.name = name;
+ this.salary = salary;
+ hireDay = LocalDate.of(year, month, day);
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public double getSalary()
+ {
+ return salary;
+ }
+
+ public LocalDate getHireDay()
+ {
+ return hireDay;
+ }
+
+ public void raiseSalary(double byPercent)
+ {
+ double raise = salary * byPercent / 100;
+ salary += raise;
+ }
+
+ public boolean equals(Object otherObject)
+ {
+ // a quick test to see if the objects are identical
+ if (this == otherObject) return true;
+
+ // must return false if the explicit parameter is null
+ if (otherObject == null) return false;
+
+ // if the classes don't match, they can't be equal
+ if (getClass() != otherObject.getClass()) return false;
+
+ // now we know otherObject is a non-null Employee
+ Employee other = (Employee) otherObject;
+
+ // test whether the fields have identical values
+ return Objects.equals(name, other.name) && salary == other.salary && Objects.equals(hireDay, other.hireDay);
+ }
+
+ public int hashCode()
+ {
+ return Objects.hash(name, salary, hireDay);
+ }
+
+ public String toString()
+ {
+ return getClass().getName() + "[name=" + name + ",salary=" + salary + ",hireDay=" + hireDay
+ + "]";
+ }
+}
diff --git a/corejava第10版/v1ch05/equals/EqualsTest.java b/corejava第10版/v1ch05/equals/EqualsTest.java
new file mode 100644
index 0000000..f37d5b3
--- /dev/null
+++ b/corejava第10版/v1ch05/equals/EqualsTest.java
@@ -0,0 +1,37 @@
+package equals;
+
+/**
+ * This program demonstrates the equals method.
+ * @version 1.12 2012-01-26
+ * @author Cay Horstmann
+ */
+public class EqualsTest
+{
+ public static void main(String[] args)
+ {
+ Employee alice1 = new Employee("Alice Adams", 75000, 1987, 12, 15);
+ Employee alice2 = alice1;
+ Employee alice3 = new Employee("Alice Adams", 75000, 1987, 12, 15);
+ Employee bob = new Employee("Bob Brandson", 50000, 1989, 10, 1);
+
+ System.out.println("alice1 == alice2: " + (alice1 == alice2));
+
+ System.out.println("alice1 == alice3: " + (alice1 == alice3));
+
+ System.out.println("alice1.equals(alice3): " + alice1.equals(alice3));
+
+ System.out.println("alice1.equals(bob): " + alice1.equals(bob));
+
+ System.out.println("bob.toString(): " + bob);
+
+ Manager carl = new Manager("Carl Cracker", 80000, 1987, 12, 15);
+ Manager boss = new Manager("Carl Cracker", 80000, 1987, 12, 15);
+ boss.setBonus(5000);
+ System.out.println("boss.toString(): " + boss);
+ System.out.println("carl.equals(boss): " + carl.equals(boss));
+ System.out.println("alice1.hashCode(): " + alice1.hashCode());
+ System.out.println("alice3.hashCode(): " + alice3.hashCode());
+ System.out.println("bob.hashCode(): " + bob.hashCode());
+ System.out.println("carl.hashCode(): " + carl.hashCode());
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch05/equals/Manager.java b/corejava第10版/v1ch05/equals/Manager.java
new file mode 100644
index 0000000..85589ec
--- /dev/null
+++ b/corejava第10版/v1ch05/equals/Manager.java
@@ -0,0 +1,42 @@
+package equals;
+
+public class Manager extends Employee
+{
+ private double bonus;
+
+ public Manager(String name, double salary, int year, int month, int day)
+ {
+ super(name, salary, year, month, day);
+ bonus = 0;
+ }
+
+ public double getSalary()
+ {
+ double baseSalary = super.getSalary();
+ return baseSalary + bonus;
+ }
+
+ public void setBonus(double bonus)
+ {
+ this.bonus = bonus;
+ }
+
+ public boolean equals(Object otherObject)
+ {
+ if (!super.equals(otherObject)) return false;
+ Manager other = (Manager) otherObject;
+ // super.equals checked that this and other belong to the same class
+ return bonus == other.bonus;
+ }
+
+ public int hashCode()
+ {
+ return java.util.Objects.hash(super.hashCode(), bonus);
+ }
+
+ public String toString()
+ {
+ return super.toString() + "[bonus=" + bonus + "]";
+ }
+}
+
diff --git a/javacore第11版/corejava/v1ch05/inheritance/Employee.java b/corejava第10版/v1ch05/inheritance/Employee.java
similarity index 100%
rename from javacore第11版/corejava/v1ch05/inheritance/Employee.java
rename to corejava第10版/v1ch05/inheritance/Employee.java
diff --git a/corejava第10版/v1ch05/inheritance/Manager.java b/corejava第10版/v1ch05/inheritance/Manager.java
new file mode 100644
index 0000000..4d3fc28
--- /dev/null
+++ b/corejava第10版/v1ch05/inheritance/Manager.java
@@ -0,0 +1,30 @@
+package inheritance;
+
+public class Manager extends Employee
+{
+ private double bonus;
+
+ /**
+ * @param name the employee's name
+ * @param salary the salary
+ * @param year the hire year
+ * @param month the hire month
+ * @param day the hire day
+ */
+ public Manager(String name, double salary, int year, int month, int day)
+ {
+ super(name, salary, year, month, day);
+ bonus = 0;
+ }
+
+ public double getSalary()
+ {
+ double baseSalary = super.getSalary();
+ return baseSalary + bonus;
+ }
+
+ public void setBonus(double b)
+ {
+ bonus = b;
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch05/inheritance/ManagerTest.java b/corejava第10版/v1ch05/inheritance/ManagerTest.java
new file mode 100644
index 0000000..88f7b06
--- /dev/null
+++ b/corejava第10版/v1ch05/inheritance/ManagerTest.java
@@ -0,0 +1,28 @@
+package inheritance;
+
+/**
+ * This program demonstrates inheritance.
+ * @version 1.21 2004-02-21
+ * @author Cay Horstmann
+ */
+public class ManagerTest
+{
+ public static void main(String[] args)
+ {
+ // construct a Manager object
+ Manager boss = new Manager("Carl Cracker", 80000, 1987, 12, 15);
+ boss.setBonus(5000);
+
+ Employee[] staff = new Employee[3];
+
+ // fill the staff array with Manager and Employee objects
+
+ staff[0] = boss;
+ staff[1] = new Employee("Harry Hacker", 50000, 1989, 10, 1);
+ staff[2] = new Employee("Tommy Tester", 40000, 1990, 3, 15);
+
+ // print out information about all Employee objects
+ for (Employee e : staff)
+ System.out.println("name=" + e.getName() + ",salary=" + e.getSalary());
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch05/methods/MethodTableTest.java b/corejava第10版/v1ch05/methods/MethodTableTest.java
new file mode 100644
index 0000000..c84666d
--- /dev/null
+++ b/corejava第10版/v1ch05/methods/MethodTableTest.java
@@ -0,0 +1,61 @@
+package methods;
+
+import java.lang.reflect.*;
+
+/**
+ * This program shows how to invoke methods through reflection.
+ * @version 1.2 2012-05-04
+ * @author Cay Horstmann
+ */
+public class MethodTableTest
+{
+ public static void main(String[] args) throws Exception
+ {
+ // get method pointers to the square and sqrt methods
+ Method square = MethodTableTest.class.getMethod("square", double.class);
+ Method sqrt = Math.class.getMethod("sqrt", double.class);
+
+ // print tables of x- and y-values
+
+ printTable(1, 10, 10, square);
+ printTable(1, 10, 10, sqrt);
+ }
+
+ /**
+ * Returns the square of a number
+ * @param x a number
+ * @return x squared
+ */
+ public static double square(double x)
+ {
+ return x * x;
+ }
+
+ /**
+ * Prints a table with x- and y-values for a method
+ * @param from the lower bound for the x-values
+ * @param to the upper bound for the x-values
+ * @param n the number of rows in the table
+ * @param f a method with a double parameter and double return value
+ */
+ public static void printTable(double from, double to, int n, Method f)
+ {
+ // print out the method as table header
+ System.out.println(f);
+
+ double dx = (to - from) / (n - 1);
+
+ for (double x = from; x <= to; x += dx)
+ {
+ try
+ {
+ double y = (Double) f.invoke(null, x);
+ System.out.printf("%10.4f | %10.4f%n", x, y);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+}
diff --git a/corejava第10版/v1ch05/objectAnalyzer/ObjectAnalyzer.java b/corejava第10版/v1ch05/objectAnalyzer/ObjectAnalyzer.java
new file mode 100644
index 0000000..85e81d0
--- /dev/null
+++ b/corejava第10版/v1ch05/objectAnalyzer/ObjectAnalyzer.java
@@ -0,0 +1,73 @@
+package objectAnalyzer;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+
+public class ObjectAnalyzer
+{
+ private ArrayList visited = new ArrayList<>();
+
+ /**
+ * Converts an object to a string representation that lists all fields.
+ * @param obj an object
+ * @return a string with the object's class name and all field names and
+ * values
+ */
+ public String toString(Object obj)
+ {
+ if (obj == null) return "null";
+ if (visited.contains(obj)) return "...";
+ visited.add(obj);
+ Class cl = obj.getClass();
+ if (cl == String.class) return (String) obj;
+ if (cl.isArray())
+ {
+ String r = cl.getComponentType() + "[]{";
+ for (int i = 0; i < Array.getLength(obj); i++)
+ {
+ if (i > 0) r += ",";
+ Object val = Array.get(obj, i);
+ if (cl.getComponentType().isPrimitive()) r += val;
+ else r += toString(val);
+ }
+ return r + "}";
+ }
+
+ String r = cl.getName();
+ // inspect the fields of this class and all superclasses
+ do
+ {
+ r += "[";
+ Field[] fields = cl.getDeclaredFields();
+ AccessibleObject.setAccessible(fields, true);
+ // get the names and values of all fields
+ for (Field f : fields)
+ {
+ if (!Modifier.isStatic(f.getModifiers()))
+ {
+ if (!r.endsWith("[")) r += ",";
+ r += f.getName() + "=";
+ try
+ {
+ Class t = f.getType();
+ Object val = f.get(obj);
+ if (t.isPrimitive()) r += val;
+ else r += toString(val);
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+ r += "]";
+ cl = cl.getSuperclass();
+ }
+ while (cl != null);
+
+ return r;
+ }
+}
diff --git a/corejava第10版/v1ch05/objectAnalyzer/ObjectAnalyzerTest.java b/corejava第10版/v1ch05/objectAnalyzer/ObjectAnalyzerTest.java
new file mode 100644
index 0000000..dac6ee8
--- /dev/null
+++ b/corejava第10版/v1ch05/objectAnalyzer/ObjectAnalyzerTest.java
@@ -0,0 +1,19 @@
+package objectAnalyzer;
+
+import java.util.ArrayList;
+
+/**
+ * This program uses reflection to spy on objects.
+ * @version 1.12 2012-01-26
+ * @author Cay Horstmann
+ */
+public class ObjectAnalyzerTest
+{
+ public static void main(String[] args)
+ {
+ ArrayList squares = new ArrayList<>();
+ for (int i = 1; i <= 5; i++)
+ squares.add(i * i);
+ System.out.println(new ObjectAnalyzer().toString(squares));
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch05/reflection/ReflectionTest.java b/corejava第10版/v1ch05/reflection/ReflectionTest.java
new file mode 100644
index 0000000..c7eb8a0
--- /dev/null
+++ b/corejava第10版/v1ch05/reflection/ReflectionTest.java
@@ -0,0 +1,126 @@
+package reflection;
+
+import java.util.*;
+import java.lang.reflect.*;
+
+/**
+ * This program uses reflection to print all features of a class.
+ * @version 1.1 2004-02-21
+ * @author Cay Horstmann
+ */
+public class ReflectionTest
+{
+ 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.Date): ");
+ name = in.next();
+ }
+
+ try
+ {
+ // print class name and superclass name (if != Object)
+ Class cl = Class.forName(name);
+ Class supercl = cl.getSuperclass();
+ String modifiers = Modifier.toString(cl.getModifiers());
+ if (modifiers.length() > 0) System.out.print(modifiers + " ");
+ System.out.print("class " + name);
+ if (supercl != null && supercl != Object.class) System.out.print(" extends "
+ + supercl.getName());
+
+ System.out.print("\n{\n");
+ printConstructors(cl);
+ System.out.println();
+ printMethods(cl);
+ System.out.println();
+ printFields(cl);
+ System.out.println("}");
+ }
+ catch (ClassNotFoundException e)
+ {
+ e.printStackTrace();
+ }
+ System.exit(0);
+ }
+
+ /**
+ * Prints all constructors of a class
+ * @param cl a class
+ */
+ public static void printConstructors(Class cl)
+ {
+ Constructor[] constructors = cl.getDeclaredConstructors();
+
+ for (Constructor c : constructors)
+ {
+ String name = c.getName();
+ System.out.print(" ");
+ String modifiers = Modifier.toString(c.getModifiers());
+ if (modifiers.length() > 0) System.out.print(modifiers + " ");
+ System.out.print(name + "(");
+
+ // print parameter types
+ Class[] paramTypes = c.getParameterTypes();
+ for (int j = 0; j < paramTypes.length; j++)
+ {
+ if (j > 0) System.out.print(", ");
+ System.out.print(paramTypes[j].getName());
+ }
+ System.out.println(");");
+ }
+ }
+
+ /**
+ * Prints all methods of a class
+ * @param cl a class
+ */
+ public static void printMethods(Class cl)
+ {
+ Method[] methods = cl.getDeclaredMethods();
+
+ for (Method m : methods)
+ {
+ Class retType = m.getReturnType();
+ String name = m.getName();
+
+ System.out.print(" ");
+ // print modifiers, return type and method name
+ String modifiers = Modifier.toString(m.getModifiers());
+ if (modifiers.length() > 0) System.out.print(modifiers + " ");
+ System.out.print(retType.getName() + " " + name + "(");
+
+ // print parameter types
+ Class[] paramTypes = m.getParameterTypes();
+ for (int j = 0; j < paramTypes.length; j++)
+ {
+ if (j > 0) System.out.print(", ");
+ System.out.print(paramTypes[j].getName());
+ }
+ System.out.println(");");
+ }
+ }
+
+ /**
+ * Prints all fields of a class
+ * @param cl a class
+ */
+ public static void printFields(Class cl)
+ {
+ Field[] fields = cl.getDeclaredFields();
+
+ for (Field f : fields)
+ {
+ Class type = f.getType();
+ String name = f.getName();
+ System.out.print(" ");
+ String modifiers = Modifier.toString(f.getModifiers());
+ if (modifiers.length() > 0) System.out.print(modifiers + " ");
+ System.out.println(type.getName() + " " + name + ";");
+ }
+ }
+}
diff --git a/corejava第10版/v1ch06/anonymousInnerClass/AnonymousInnerClassTest.java b/corejava第10版/v1ch06/anonymousInnerClass/AnonymousInnerClassTest.java
new file mode 100644
index 0000000..9a4bc7d
--- /dev/null
+++ b/corejava第10版/v1ch06/anonymousInnerClass/AnonymousInnerClassTest.java
@@ -0,0 +1,50 @@
+package anonymousInnerClass;
+
+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.11 2015-05-12
+ * @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, boolean beep)
+ {
+ ActionListener listener = new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ System.out.println("At the tone, the time is " + new Date());
+ if (beep) Toolkit.getDefaultToolkit().beep();
+ }
+ };
+ Timer t = new Timer(interval, listener);
+ t.start();
+ }
+}
diff --git a/corejava第10版/v1ch06/clone/CloneTest.java b/corejava第10版/v1ch06/clone/CloneTest.java
new file mode 100644
index 0000000..6e940d1
--- /dev/null
+++ b/corejava第10版/v1ch06/clone/CloneTest.java
@@ -0,0 +1,27 @@
+package clone;
+
+/**
+ * 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();
+ }
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch06/clone/Employee.java b/corejava第10版/v1ch06/clone/Employee.java
new file mode 100644
index 0000000..eb113b4
--- /dev/null
+++ b/corejava第10版/v1ch06/clone/Employee.java
@@ -0,0 +1,54 @@
+package clone;
+
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+public class Employee implements Cloneable
+{
+ private String name;
+ private double salary;
+ private Date hireDay;
+
+ public Employee(String name, double salary)
+ {
+ this.name = name;
+ this.salary = salary;
+ 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 + "]";
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch06/innerClass/InnerClassTest.java b/corejava第10版/v1ch06/innerClass/InnerClassTest.java
new file mode 100644
index 0000000..dfb0ac4
--- /dev/null
+++ b/corejava第10版/v1ch06/innerClass/InnerClassTest.java
@@ -0,0 +1,64 @@
+package innerClass;
+
+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.11 2015-05-12
+ * @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
+{
+ private int interval;
+ private boolean beep;
+
+ /**
+ * 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();
+ }
+
+ public class TimePrinter implements ActionListener
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ System.out.println("At the tone, the time is " + new Date());
+ if (beep) Toolkit.getDefaultToolkit().beep();
+ }
+ }
+}
diff --git a/corejava第10版/v1ch06/interfaces/Employee.java b/corejava第10版/v1ch06/interfaces/Employee.java
new file mode 100644
index 0000000..d2e5ff7
--- /dev/null
+++ b/corejava第10版/v1ch06/interfaces/Employee.java
@@ -0,0 +1,40 @@
+package interfaces;
+
+public class Employee implements Comparable
+{
+ private String name;
+ private double salary;
+
+ public Employee(String name, double salary)
+ {
+ this.name = name;
+ this.salary = salary;
+ }
+
+ 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)
+ {
+ return Double.compare(salary, other.salary);
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch06/interfaces/EmployeeSortTest.java b/corejava第10版/v1ch06/interfaces/EmployeeSortTest.java
new file mode 100644
index 0000000..43d0104
--- /dev/null
+++ b/corejava第10版/v1ch06/interfaces/EmployeeSortTest.java
@@ -0,0 +1,26 @@
+package interfaces;
+
+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());
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch06/lambda/LambdaTest.java b/corejava第10版/v1ch06/lambda/LambdaTest.java
new file mode 100644
index 0000000..efe3b7c
--- /dev/null
+++ b/corejava第10版/v1ch06/lambda/LambdaTest.java
@@ -0,0 +1,35 @@
+package lambda;
+
+import java.util.*;
+
+import javax.swing.*;
+import javax.swing.Timer;
+
+/**
+ * This program demonstrates the use of lambda expressions.
+ * @version 1.0 2015-05-12
+ * @author Cay Horstmann
+ */
+public class LambdaTest
+{
+ public static void main(String[] args)
+ {
+ String[] planets = new String[] { "Mercury", "Venus", "Earth", "Mars",
+ "Jupiter", "Saturn", "Uranus", "Neptune" };
+ System.out.println(Arrays.toString(planets));
+ System.out.println("Sorted in dictionary order:");
+ Arrays.sort(planets);
+ System.out.println(Arrays.toString(planets));
+ System.out.println("Sorted by length:");
+ Arrays.sort(planets, (first, second) -> first.length() - second.length());
+ System.out.println(Arrays.toString(planets));
+
+ Timer t = new Timer(1000, event ->
+ System.out.println("The time is " + new Date()));
+ t.start();
+
+ // keep program running until user selects "Ok"
+ JOptionPane.showMessageDialog(null, "Quit program?");
+ System.exit(0);
+ }
+}
diff --git a/corejava第10版/v1ch06/localInnerClass/LocalInnerClassTest.java b/corejava第10版/v1ch06/localInnerClass/LocalInnerClassTest.java
new file mode 100644
index 0000000..08519f1
--- /dev/null
+++ b/corejava第10版/v1ch06/localInnerClass/LocalInnerClassTest.java
@@ -0,0 +1,51 @@
+package localInnerClass;
+
+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.01 2015-05-12
+ * @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, boolean beep)
+ {
+ class TimePrinter implements ActionListener
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ System.out.println("At the tone, the time is " + new Date());
+ if (beep) Toolkit.getDefaultToolkit().beep();
+ }
+ }
+ ActionListener listener = new TimePrinter();
+ Timer t = new Timer(interval, listener);
+ t.start();
+ }
+}
diff --git a/corejava第10版/v1ch06/proxy/ProxyTest.java b/corejava第10版/v1ch06/proxy/ProxyTest.java
new file mode 100644
index 0000000..b3c1a3b
--- /dev/null
+++ b/corejava第10版/v1ch06/proxy/ProxyTest.java
@@ -0,0 +1,74 @@
+package proxy;
+
+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
+{
+ private Object target;
+
+ /**
+ * 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);
+ }
+}
diff --git a/corejava第10版/v1ch06/staticInnerClass/StaticInnerClassTest.java b/corejava第10版/v1ch06/staticInnerClass/StaticInnerClassTest.java
new file mode 100644
index 0000000..ea90626
--- /dev/null
+++ b/corejava第10版/v1ch06/staticInnerClass/StaticInnerClassTest.java
@@ -0,0 +1,78 @@
+package staticInnerClass;
+
+/**
+ * This program demonstrates the use of static inner classes.
+ * @version 1.02 2015-05-12
+ * @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
+ {
+ private double first;
+ private double second;
+
+ /**
+ * 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;
+ }
+ }
+
+ /**
+ * 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.POSITIVE_INFINITY;
+ double max = Double.NEGATIVE_INFINITY;
+ for (double v : values)
+ {
+ if (min > v) min = v;
+ if (max < v) max = v;
+ }
+ return new Pair(min, max);
+ }
+}
diff --git a/corejava第10版/v1ch06/timer/TimerTest.java b/corejava第10版/v1ch06/timer/TimerTest.java
new file mode 100644
index 0000000..7e16122
--- /dev/null
+++ b/corejava第10版/v1ch06/timer/TimerTest.java
@@ -0,0 +1,38 @@
+package timer;
+
+/**
+ @version 1.01 2015-05-12
+ @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)
+ {
+ System.out.println("At the tone, the time is " + new Date());
+ Toolkit.getDefaultToolkit().beep();
+ }
+}
diff --git a/corejava第10版/v1ch07/except/ExceptTest.java b/corejava第10版/v1ch07/except/ExceptTest.java
new file mode 100644
index 0000000..9a71fe8
--- /dev/null
+++ b/corejava第10版/v1ch07/except/ExceptTest.java
@@ -0,0 +1,174 @@
+package except;
+
+import java.awt.EventQueue;
+import java.awt.event.*;
+import java.io.*;
+import java.nio.file.*;
+import java.util.*;
+import javax.swing.*;
+
+/**
+ * @version 1.34 2015-08-20
+ * @author Cay Horstmann
+ */
+public class ExceptTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new ExceptTestFrame();
+ frame.setTitle("ExceptTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * A frame with a panel for testing various exceptions
+ */
+class ExceptTestFrame extends JFrame
+{
+ public ExceptTestFrame()
+ {
+ ExceptTestPanel panel = new ExceptTestPanel();
+ add(panel);
+ pack();
+ }
+}
+
+/**
+ * A panel with radio buttons for running code snippets and studying their exception behavior
+ */
+class ExceptTestPanel extends Box
+{
+ private ButtonGroup group;
+ private JTextField textField;
+ private double[] a = new double[10];
+
+ public ExceptTestPanel()
+ {
+ super(BoxLayout.Y_AXIS);
+ group = new ButtonGroup();
+
+ // add radio buttons for code snippets
+
+ addRadioButton("Integer divide by zero", new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ a[1] = 1 / (a.length - a.length);
+ }
+ });
+
+ addRadioButton("Floating point divide by zero", new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ a[1] = a[2] / (a[3] - a[3]);
+ }
+ });
+
+ addRadioButton("Array bounds", new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ a[1] = a[10];
+ }
+ });
+
+ addRadioButton("Bad cast", new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ a = (double[]) event.getSource();
+ }
+ });
+
+ addRadioButton("Null pointer", new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ System.out.println(textField.getAction().toString());
+ }
+ });
+
+ addRadioButton("sqrt(-1)", new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ a[1] = Math.sqrt(-1);
+ }
+ });
+
+ addRadioButton("Overflow", new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ a[1] = 1000 * 1000 * 1000 * 1000;
+ int n = (int) a[1];
+ System.out.println(n);
+ }
+ });
+
+ addRadioButton("No such file", new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ try
+ {
+ System.out.println(
+ new Scanner(Paths.get("woozle.txt"), "UTF-8").next());
+ }
+ catch (IOException e)
+ {
+ textField.setText(e.toString());
+ }
+ }
+ });
+
+ addRadioButton("Throw unknown", new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ throw new UnknownError();
+ }
+ });
+
+ // add the text field for exception display
+ textField = new JTextField(30);
+ add(textField);
+ }
+
+ /**
+ * Adds a radio button with a given listener to the panel. Traps any exceptions in the
+ * actionPerformed method of the listener.
+ * @param s the label of the radio button
+ * @param listener the action listener for the radio button
+ */
+ private void addRadioButton(String s, ActionListener listener)
+ {
+ JRadioButton button = new JRadioButton(s, false)
+ {
+ // the button calls this method to fire an
+ // action event. We override it to trap exceptions
+ protected void fireActionPerformed(ActionEvent event)
+ {
+ try
+ {
+ textField.setText("No exception");
+ super.fireActionPerformed(event);
+ }
+ catch (Exception e)
+ {
+ textField.setText(e.toString());
+ }
+ }
+ };
+
+ button.addActionListener(listener);
+ add(button);
+ group.add(button);
+ }
+}
diff --git a/corejava第10版/v1ch07/except/manifest.mf b/corejava第10版/v1ch07/except/manifest.mf
new file mode 100644
index 0000000..328e8e5
--- /dev/null
+++ b/corejava第10版/v1ch07/except/manifest.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+X-COMMENT: Main-Class will be added automatically by build
+
diff --git a/corejava第10版/v1ch07/exceptional/ExceptionalTest.java b/corejava第10版/v1ch07/exceptional/ExceptionalTest.java
new file mode 100644
index 0000000..ed1ea57
--- /dev/null
+++ b/corejava第10版/v1ch07/exceptional/ExceptionalTest.java
@@ -0,0 +1,43 @@
+package exceptional;
+
+import java.util.*;
+
+/**
+ * @version 1.11 2012-01-26
+ * @author Cay Horstmann
+ */
+public class ExceptionalTest
+{
+ public static void main(String[] args)
+ {
+ int i = 0;
+ int ntry = 10000000;
+ Stack s = new Stack<>();
+ long s1;
+ long s2;
+
+ // test a stack for emptiness ntry times
+ System.out.println("Testing for empty stack");
+ s1 = new Date().getTime();
+ for (i = 0; i <= ntry; i++)
+ if (!s.empty()) s.pop();
+ s2 = new Date().getTime();
+ System.out.println((s2 - s1) + " milliseconds");
+
+ // pop an empty stack ntry times and catch the resulting exception
+ System.out.println("Catching EmptyStackException");
+ s1 = new Date().getTime();
+ for (i = 0; i <= ntry; i++)
+ {
+ try
+ {
+ s.pop();
+ }
+ catch (EmptyStackException e)
+ {
+ }
+ }
+ s2 = new Date().getTime();
+ System.out.println((s2 - s1) + " milliseconds");
+ }
+}
diff --git a/corejava第10版/v1ch07/logging/LoggingImageViewer.java b/corejava第10版/v1ch07/logging/LoggingImageViewer.java
new file mode 100644
index 0000000..b70dbda
--- /dev/null
+++ b/corejava第10版/v1ch07/logging/LoggingImageViewer.java
@@ -0,0 +1,170 @@
+package logging;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.logging.*;
+import javax.swing.*;
+
+/**
+ * A modification of the image viewer program that logs various events.
+ * @version 1.03 2015-08-20
+ * @author Cay Horstmann
+ */
+public class LoggingImageViewer
+{
+ public static void main(String[] args)
+ {
+ if (System.getProperty("java.util.logging.config.class") == null
+ && System.getProperty("java.util.logging.config.file") == null)
+ {
+ try
+ {
+ Logger.getLogger("com.horstmann.corejava").setLevel(Level.ALL);
+ final int LOG_ROTATION_COUNT = 10;
+ Handler handler = new FileHandler("%h/LoggingImageViewer.log", 0, LOG_ROTATION_COUNT);
+ Logger.getLogger("com.horstmann.corejava").addHandler(handler);
+ }
+ catch (IOException e)
+ {
+ Logger.getLogger("com.horstmann.corejava").log(Level.SEVERE,
+ "Can't create log file handler", e);
+ }
+ }
+
+ EventQueue.invokeLater(() ->
+ {
+ Handler windowHandler = new WindowHandler();
+ windowHandler.setLevel(Level.ALL);
+ Logger.getLogger("com.horstmann.corejava").addHandler(windowHandler);
+
+ JFrame frame = new ImageViewerFrame();
+ frame.setTitle("LoggingImageViewer");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+
+ Logger.getLogger("com.horstmann.corejava").fine("Showing frame");
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * The frame that shows the image.
+ */
+class ImageViewerFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 400;
+
+ private JLabel label;
+ private static Logger logger = Logger.getLogger("com.horstmann.corejava");
+
+ public ImageViewerFrame()
+ {
+ logger.entering("ImageViewerFrame", "");
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ // set up menu bar
+ JMenuBar menuBar = new JMenuBar();
+ setJMenuBar(menuBar);
+
+ JMenu menu = new JMenu("File");
+ menuBar.add(menu);
+
+ JMenuItem openItem = new JMenuItem("Open");
+ menu.add(openItem);
+ openItem.addActionListener(new FileOpenListener());
+
+ JMenuItem exitItem = new JMenuItem("Exit");
+ menu.add(exitItem);
+ exitItem.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ logger.fine("Exiting.");
+ System.exit(0);
+ }
+ });
+
+ // use a label to display the images
+ label = new JLabel();
+ add(label);
+ logger.exiting("ImageViewerFrame", "");
+ }
+
+ private class FileOpenListener implements ActionListener
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ logger.entering("ImageViewerFrame.FileOpenListener", "actionPerformed", event);
+
+ // set up file chooser
+ JFileChooser chooser = new JFileChooser();
+ chooser.setCurrentDirectory(new File("."));
+
+ // accept all files ending with .gif
+ chooser.setFileFilter(new javax.swing.filechooser.FileFilter()
+ {
+ public boolean accept(File f)
+ {
+ return f.getName().toLowerCase().endsWith(".gif") || f.isDirectory();
+ }
+
+ public String getDescription()
+ {
+ return "GIF Images";
+ }
+ });
+
+ // show file chooser dialog
+ int r = chooser.showOpenDialog(ImageViewerFrame.this);
+
+ // if image file accepted, set it as icon of the label
+ if (r == JFileChooser.APPROVE_OPTION)
+ {
+ String name = chooser.getSelectedFile().getPath();
+ logger.log(Level.FINE, "Reading file {0}", name);
+ label.setIcon(new ImageIcon(name));
+ }
+ else logger.fine("File open dialog canceled.");
+ logger.exiting("ImageViewerFrame.FileOpenListener", "actionPerformed");
+ }
+ }
+}
+
+/**
+ * A handler for displaying log records in a window.
+ */
+class WindowHandler extends StreamHandler
+{
+ private JFrame frame;
+
+ public WindowHandler()
+ {
+ frame = new JFrame();
+ final JTextArea output = new JTextArea();
+ output.setEditable(false);
+ frame.setSize(200, 200);
+ frame.add(new JScrollPane(output));
+ frame.setFocusableWindowState(false);
+ frame.setVisible(true);
+ setOutputStream(new OutputStream()
+ {
+ public void write(int b)
+ {
+ } // not called
+
+ public void write(byte[] b, int off, int len)
+ {
+ output.append(new String(b, off, len));
+ }
+ });
+ }
+
+ public void publish(LogRecord record)
+ {
+ if (!frame.isVisible()) return;
+ super.publish(record);
+ flush();
+ }
+}
diff --git a/corejava第10版/v1ch07/stackTrace/StackTraceTest.java b/corejava第10版/v1ch07/stackTrace/StackTraceTest.java
new file mode 100644
index 0000000..873ecaa
--- /dev/null
+++ b/corejava第10版/v1ch07/stackTrace/StackTraceTest.java
@@ -0,0 +1,38 @@
+package stackTrace;
+
+import java.util.*;
+
+/**
+ * A program that displays a trace feature of a recursive method call.
+ * @version 1.01 2004-05-10
+ * @author Cay Horstmann
+ */
+public class StackTraceTest
+{
+ /**
+ * Computes the factorial of a number
+ * @param n a non-negative integer
+ * @return n! = 1 * 2 * . . . * n
+ */
+ public static int factorial(int n)
+ {
+ System.out.println("factorial(" + n + "):");
+ Throwable t = new Throwable();
+ StackTraceElement[] frames = t.getStackTrace();
+ for (StackTraceElement f : frames)
+ System.out.println(f);
+ int r;
+ if (n <= 1) r = 1;
+ else r = n * factorial(n - 1);
+ System.out.println("return " + r);
+ return r;
+ }
+
+ public static void main(String[] args)
+ {
+ Scanner in = new Scanner(System.in);
+ System.out.print("Enter n: ");
+ int n = in.nextInt();
+ factorial(n);
+ }
+}
diff --git a/javacore第11版/corejava/v1ch08/genericAlgorithms/GenericAlgorithms.java b/corejava第10版/v1ch08/genericAlgorithms/GenericAlgorithms.java
similarity index 100%
rename from javacore第11版/corejava/v1ch08/genericAlgorithms/GenericAlgorithms.java
rename to corejava第10版/v1ch08/genericAlgorithms/GenericAlgorithms.java
diff --git a/corejava第10版/v1ch08/genericAlgorithms/Pair.java b/corejava第10版/v1ch08/genericAlgorithms/Pair.java
new file mode 100644
index 0000000..fb3bef0
--- /dev/null
+++ b/corejava第10版/v1ch08/genericAlgorithms/Pair.java
@@ -0,0 +1,35 @@
+package genericAlgorithms;
+
+import java.util.function.Supplier;
+
+/**
+ * @version 1.00 2004-05-10
+ * @author Cay Horstmann
+ */
+public class Pair
+{
+ private T first;
+ private T second;
+
+ 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; }
+
+ public String toString() { return "(" + first + ", " + second + ")"; }
+
+ public static Pair makePair(Supplier constr)
+ {
+ return new Pair<>(constr.get(), constr.get());
+ }
+
+ public static Pair makePair(Class cl)
+ {
+ try { return new Pair<>(cl.newInstance(), cl.newInstance()); }
+ catch (Exception ex) { return null; }
+ }
+}
diff --git a/corejava第10版/v1ch08/genericReflection/GenericReflectionTest.java b/corejava第10版/v1ch08/genericReflection/GenericReflectionTest.java
new file mode 100644
index 0000000..3267c94
--- /dev/null
+++ b/corejava第10版/v1ch08/genericReflection/GenericReflectionTest.java
@@ -0,0 +1,123 @@
+package genericReflection;
+
+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
+ {
+ try (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/javacore第11版/corejava/v1ch08/pair1/Pair.java b/corejava第10版/v1ch08/pair1/Pair.java
similarity index 100%
rename from javacore第11版/corejava/v1ch08/pair1/Pair.java
rename to corejava第10版/v1ch08/pair1/Pair.java
diff --git a/corejava第10版/v1ch08/pair1/PairTest1.java b/corejava第10版/v1ch08/pair1/PairTest1.java
new file mode 100644
index 0000000..c43d9ea
--- /dev/null
+++ b/corejava第10版/v1ch08/pair1/PairTest1.java
@@ -0,0 +1,37 @@
+package pair1;
+
+/**
+ * @version 1.01 2012-01-26
+ * @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/javacore第11版/corejava/v1ch08/pair2/Pair.java b/corejava第10版/v1ch08/pair2/Pair.java
similarity index 100%
rename from javacore第11版/corejava/v1ch08/pair2/Pair.java
rename to corejava第10版/v1ch08/pair2/Pair.java
diff --git a/corejava第10版/v1ch08/pair2/PairTest2.java b/corejava第10版/v1ch08/pair2/PairTest2.java
new file mode 100644
index 0000000..302fc94
--- /dev/null
+++ b/corejava第10版/v1ch08/pair2/PairTest2.java
@@ -0,0 +1,46 @@
+package pair2;
+
+import java.time.*;
+
+/**
+ * @version 1.02 2015-06-21
+ * @author Cay Horstmann
+ */
+public class PairTest2
+{
+ public static void main(String[] args)
+ {
+ LocalDate[] birthdays =
+ {
+ LocalDate.of(1906, 12, 9), // G. Hopper
+ LocalDate.of(1815, 12, 10), // A. Lovelace
+ LocalDate.of(1903, 12, 3), // J. von Neumann
+ LocalDate.of(1910, 6, 22), // K. Zuse
+ };
+ Pair mm = ArrayAlg.minmax(birthdays);
+ System.out.println("min = " + mm.getFirst());
+ System.out.println("max = " + mm.getSecond());
+ }
+}
+
+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/javacore第11版/corejava/v1ch08/pair3/Employee.java b/corejava第10版/v1ch08/pair3/Employee.java
similarity index 100%
rename from javacore第11版/corejava/v1ch08/pair3/Employee.java
rename to corejava第10版/v1ch08/pair3/Employee.java
diff --git a/corejava第10版/v1ch08/pair3/Manager.java b/corejava第10版/v1ch08/pair3/Manager.java
new file mode 100644
index 0000000..506d164
--- /dev/null
+++ b/corejava第10版/v1ch08/pair3/Manager.java
@@ -0,0 +1,35 @@
+package pair3;
+
+public class Manager extends Employee
+{
+ private double bonus;
+
+ /**
+ @param name the employee's name
+ @param salary the salary
+ @param year the hire year
+ @param month the hire month
+ @param day the hire day
+ */
+ public Manager(String name, double salary, int year, int month, int day)
+ {
+ super(name, salary, 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;
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v1ch08/pair3/Pair.java b/corejava第10版/v1ch08/pair3/Pair.java
similarity index 100%
rename from javacore第11版/corejava/v1ch08/pair3/Pair.java
rename to corejava第10版/v1ch08/pair3/Pair.java
diff --git a/corejava第10版/v1ch08/pair3/PairTest3.java b/corejava第10版/v1ch08/pair3/PairTest3.java
new file mode 100644
index 0000000..8b9ea93
--- /dev/null
+++ b/corejava第10版/v1ch08/pair3/PairTest3.java
@@ -0,0 +1,75 @@
+package pair3;
+
+/**
+ * @version 1.01 2012-01-26
+ * @author Cay Horstmann
+ */
+public class PairTest3
+{
+ public static void main(String[] args)
+ {
+ Manager ceo = new Manager("Gus Greedy", 800000, 2003, 12, 15);
+ Manager cfo = new Manager("Sid Sneaky", 600000, 2003, 12, 15);
+ Pair buddies = new Pair<>(ceo, cfo);
+ printBuddies(buddies);
+
+ ceo.setBonus(1000000);
+ cfo.setBonus(500000);
+ Manager[] managers = { ceo, cfo };
+
+ Pair result = new Pair<>();
+ minmaxBonus(managers, result);
+ System.out.println("first: " + result.getFirst().getName()
+ + ", second: " + result.getSecond().getName());
+ maxminBonus(managers, result);
+ System.out.println("first: " + result.getFirst().getName()
+ + ", second: " + result.getSecond().getName());
+ }
+
+ public static void printBuddies(Pair extends Employee> p)
+ {
+ Employee first = p.getFirst();
+ Employee second = p.getSecond();
+ System.out.println(first.getName() + " and " + second.getName() + " are buddies.");
+ }
+
+ public static void minmaxBonus(Manager[] a, Pair super Manager> result)
+ {
+ if (a.length == 0) return;
+ Manager min = a[0];
+ Manager max = a[0];
+ for (int i = 1; i < a.length; i++)
+ {
+ if (min.getBonus() > a[i].getBonus()) min = a[i];
+ if (max.getBonus() < a[i].getBonus()) max = a[i];
+ }
+ result.setFirst(min);
+ result.setSecond(max);
+ }
+
+ public static void maxminBonus(Manager[] a, Pair super Manager> result)
+ {
+ minmaxBonus(a, result);
+ PairAlg.swapHelper(result); // OK--swapHelper captures wildcard type
+ }
+ // Can't write public static ...
+}
+
+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);
+ }
+}
+
+
diff --git a/corejava第10版/v1ch09/circularArrayQueue/CircularArrayQueueTest.java b/corejava第10版/v1ch09/circularArrayQueue/CircularArrayQueueTest.java
new file mode 100644
index 0000000..53e353a
--- /dev/null
+++ b/corejava第10版/v1ch09/circularArrayQueue/CircularArrayQueueTest.java
@@ -0,0 +1,124 @@
+package circularArrayQueue;
+
+import java.util.*;
+
+/**
+ * This program demonstrates how to extend the collections framework.
+ * @version 1.21 2012-01-26
+ * @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
+{
+ private Object[] elements;
+ private int head;
+ private int tail;
+ private int count;
+ private int modcount;
+
+ /**
+ 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
+ {
+ private int offset;
+ private int modcountAtConstruction;
+
+ 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();
+ }
+ }
+}
diff --git a/corejava第10版/v1ch09/linkedList/LinkedListTest.java b/corejava第10版/v1ch09/linkedList/LinkedListTest.java
new file mode 100644
index 0000000..9895a01
--- /dev/null
+++ b/corejava第10版/v1ch09/linkedList/LinkedListTest.java
@@ -0,0 +1,59 @@
+package linkedList;
+
+import java.util.*;
+
+/**
+ * This program demonstrates operations on linked lists.
+ * @version 1.11 2012-01-26
+ * @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/javacore第11版/corejava/v1ch09/map/Employee.java b/corejava第10版/v1ch09/map/Employee.java
similarity index 100%
rename from javacore第11版/corejava/v1ch09/map/Employee.java
rename to corejava第10版/v1ch09/map/Employee.java
diff --git a/corejava第10版/v1ch09/map/MapTest.java b/corejava第10版/v1ch09/map/MapTest.java
new file mode 100644
index 0000000..25ce9e2
--- /dev/null
+++ b/corejava第10版/v1ch09/map/MapTest.java
@@ -0,0 +1,42 @@
+package map;
+
+import java.util.*;
+
+/**
+ * This program demonstrates the use of a map with key type String and value type Employee.
+ * @version 1.12 2015-06-21
+ * @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
+
+ staff.forEach((k, v) ->
+ System.out.println("key=" + k + ", value=" + v));
+ }
+}
+
diff --git a/corejava第10版/v1ch09/priorityQueue/PriorityQueueTest.java b/corejava第10版/v1ch09/priorityQueue/PriorityQueueTest.java
new file mode 100644
index 0000000..398371a
--- /dev/null
+++ b/corejava第10版/v1ch09/priorityQueue/PriorityQueueTest.java
@@ -0,0 +1,28 @@
+package priorityQueue;
+
+import java.util.*;
+import java.time.*;
+
+/**
+ * This program demonstrates the use of a priority queue.
+ * @version 1.02 2015-06-20
+ * @author Cay Horstmann
+ */
+public class PriorityQueueTest
+{
+ public static void main(String[] args)
+ {
+ PriorityQueue pq = new PriorityQueue<>();
+ pq.add(LocalDate.of(1906, 12, 9)); // G. Hopper
+ pq.add(LocalDate.of(1815, 12, 10)); // A. Lovelace
+ pq.add(LocalDate.of(1903, 12, 3)); // J. von Neumann
+ pq.add(LocalDate.of(1910, 6, 22)); // K. Zuse
+
+ System.out.println("Iterating over elements...");
+ for (LocalDate date : pq)
+ System.out.println(date);
+ System.out.println("Removing elements...");
+ while (!pq.isEmpty())
+ System.out.println(pq.remove());
+ }
+}
diff --git a/corejava第10版/v1ch09/set/SetTest.java b/corejava第10版/v1ch09/set/SetTest.java
new file mode 100644
index 0000000..216c1c5
--- /dev/null
+++ b/corejava第10版/v1ch09/set/SetTest.java
@@ -0,0 +1,35 @@
+package set;
+
+import java.util.*;
+
+/**
+ * This program uses a set to print all unique words in System.in.
+ * @version 1.12 2015-06-21
+ * @author Cay Horstmann
+ */
+public class SetTest
+{
+ public static void main(String[] args)
+ {
+ Set words = new HashSet<>(); // HashSet implements Set
+ long totalTime = 0;
+
+ try (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 && iter.hasNext(); i++)
+ System.out.println(iter.next());
+ System.out.println(". . .");
+ System.out.println(words.size() + " distinct words. " + totalTime + " milliseconds.");
+ }
+}
diff --git a/corejava第10版/v1ch09/shuffle/ShuffleTest.java b/corejava第10版/v1ch09/shuffle/ShuffleTest.java
new file mode 100644
index 0000000..d83580d
--- /dev/null
+++ b/corejava第10版/v1ch09/shuffle/ShuffleTest.java
@@ -0,0 +1,22 @@
+package shuffle;
+
+import java.util.*;
+
+/**
+ * This program demonstrates the random shuffle and sort algorithms.
+ * @version 1.11 2012-01-26
+ * @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/corejava第10版/v1ch09/sieve/Sieve.java b/corejava第10版/v1ch09/sieve/Sieve.java
new file mode 100644
index 0000000..75a1634
--- /dev/null
+++ b/corejava第10版/v1ch09/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/javacore第11版/corejava/v1ch09/sieve/sieve.cpp b/corejava第10版/v1ch09/sieve/sieve.cpp
similarity index 100%
rename from javacore第11版/corejava/v1ch09/sieve/sieve.cpp
rename to corejava第10版/v1ch09/sieve/sieve.cpp
diff --git a/corejava第10版/v1ch09/treeSet/Item.java b/corejava第10版/v1ch09/treeSet/Item.java
new file mode 100644
index 0000000..3a811a4
--- /dev/null
+++ b/corejava第10版/v1ch09/treeSet/Item.java
@@ -0,0 +1,61 @@
+package treeSet;
+
+import java.util.*;
+
+/**
+ * An item with a description and a part number.
+ */
+public class Item implements Comparable-
+{
+ private String description;
+ private int partNumber;
+
+ /**
+ * 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 "[description=" + 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 Objects.equals(description, other.description) && partNumber == other.partNumber;
+ }
+
+ public int hashCode()
+ {
+ return Objects.hash(description, partNumber);
+ }
+
+ public int compareTo(Item other)
+ {
+ int diff = Integer.compare(partNumber, other.partNumber);
+ return diff != 0 ? diff : description.compareTo(other.description);
+ }
+}
diff --git a/corejava第10版/v1ch09/treeSet/TreeSetTest.java b/corejava第10版/v1ch09/treeSet/TreeSetTest.java
new file mode 100644
index 0000000..da225df
--- /dev/null
+++ b/corejava第10版/v1ch09/treeSet/TreeSetTest.java
@@ -0,0 +1,26 @@
+package treeSet;
+
+import java.util.*;
+
+/**
+ * This program sorts a set of item by comparing their descriptions.
+ * @version 1.12 2015-06-21
+ * @author Cay Horstmann
+ */
+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);
+
+ NavigableSet
- sortByDescription = new TreeSet<>(
+ Comparator.comparing(Item::getDescription));
+
+ sortByDescription.addAll(parts);
+ System.out.println(sortByDescription);
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v1ch10/blue-ball.gif b/corejava第10版/v1ch10/blue-ball.gif
similarity index 100%
rename from javacore第11版/corejava/v1ch10/blue-ball.gif
rename to corejava第10版/v1ch10/blue-ball.gif
diff --git a/corejava第10版/v1ch10/draw/DrawTest.java b/corejava第10版/v1ch10/draw/DrawTest.java
new file mode 100644
index 0000000..2e67e23
--- /dev/null
+++ b/corejava第10版/v1ch10/draw/DrawTest.java
@@ -0,0 +1,81 @@
+package draw;
+
+import java.awt.*;
+import java.awt.geom.*;
+import javax.swing.*;
+
+/**
+ * @version 1.33 2007-05-12
+ * @author Cay Horstmann
+ */
+public class DrawTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new DrawFrame();
+ frame.setTitle("DrawTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * A frame that contains a panel with drawings
+ */
+class DrawFrame extends JFrame
+{
+ public DrawFrame()
+ {
+ add(new DrawComponent());
+ pack();
+ }
+}
+
+/**
+ * A component that displays rectangles and ellipses.
+ */
+class DrawComponent extends JComponent
+{
+ private static final int DEFAULT_WIDTH = 400;
+ private static final int DEFAULT_HEIGHT = 400;
+
+ public void paintComponent(Graphics g)
+ {
+ Graphics2D g2 = (Graphics2D) g;
+
+ // draw a rectangle
+
+ double leftX = 100;
+ double topY = 100;
+ double width = 200;
+ double height = 150;
+
+ Rectangle2D rect = new Rectangle2D.Double(leftX, topY, width, height);
+ g2.draw(rect);
+
+ // draw the enclosed ellipse
+
+ Ellipse2D ellipse = new Ellipse2D.Double();
+ ellipse.setFrame(rect);
+ g2.draw(ellipse);
+
+ // draw a diagonal line
+
+ g2.draw(new Line2D.Double(leftX, topY, leftX + width, topY + height));
+
+ // draw a circle with the same center
+
+ double centerX = rect.getCenterX();
+ double centerY = rect.getCenterY();
+ double radius = 150;
+
+ Ellipse2D circle = new Ellipse2D.Double();
+ circle.setFrameFromCenter(centerX, centerY, centerX + radius, centerY + radius);
+ g2.draw(circle);
+ }
+
+ public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); }
+}
diff --git a/corejava第10版/v1ch10/fill/FillTest.java b/corejava第10版/v1ch10/fill/FillTest.java
new file mode 100644
index 0000000..f5f4428
--- /dev/null
+++ b/corejava第10版/v1ch10/fill/FillTest.java
@@ -0,0 +1,71 @@
+package fill;
+
+import java.awt.*;
+import java.awt.geom.*;
+import javax.swing.*;
+
+/**
+ * @version 1.34 2015-05-12
+ * @author Cay Horstmann
+ */
+public class FillTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new FillFrame();
+ frame.setTitle("FillTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * A frame that contains a component with drawings
+ */
+class FillFrame extends JFrame
+{
+ public FillFrame()
+ {
+ add(new FillComponent());
+ pack();
+ }
+}
+
+/**
+ * A component that displays filled rectangles and ellipses
+ */
+class FillComponent extends JComponent
+{
+ private static final int DEFAULT_WIDTH = 400;
+ private static final int DEFAULT_HEIGHT = 400;
+
+ public void paintComponent(Graphics g)
+ {
+ Graphics2D g2 = (Graphics2D) g;
+
+ // draw a rectangle
+
+ double leftX = 100;
+ double topY = 100;
+ double width = 200;
+ double height = 150;
+
+ Rectangle2D rect = new Rectangle2D.Double(leftX, topY, width, height);
+ g2.setPaint(Color.BLACK);
+ g2.draw(rect);
+ g2.setPaint(Color.RED);
+ g2.fill(rect); // Note that the right and bottom edge are not painted over
+
+ // draw the enclosed ellipse
+
+ Ellipse2D ellipse = new Ellipse2D.Double();
+ ellipse.setFrame(rect);
+ g2.setPaint(new Color(0, 128, 128)); // a dull blue-green
+ g2.fill(ellipse);
+ }
+
+ public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); }
+}
diff --git a/corejava第10版/v1ch10/font/FontTest.java b/corejava第10版/v1ch10/font/FontTest.java
new file mode 100644
index 0000000..b821219
--- /dev/null
+++ b/corejava第10版/v1ch10/font/FontTest.java
@@ -0,0 +1,87 @@
+package font;
+
+import java.awt.*;
+import java.awt.font.*;
+import java.awt.geom.*;
+import javax.swing.*;
+
+/**
+ * @version 1.34 2015-05-12
+ * @author Cay Horstmann
+ */
+public class FontTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new FontFrame();
+ frame.setTitle("FontTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * A frame with a text message component
+ */
+class FontFrame extends JFrame
+{
+ public FontFrame()
+ {
+ add(new FontComponent());
+ pack();
+ }
+}
+
+/**
+ * A component that shows a centered message in a box.
+ */
+class FontComponent extends JComponent
+{
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 200;
+
+ public void paintComponent(Graphics g)
+ {
+ Graphics2D g2 = (Graphics2D) g;
+
+ String message = "Hello, World!";
+
+ Font f = new Font("Serif", Font.BOLD, 36);
+ g2.setFont(f);
+
+ // measure the size of the message
+
+ FontRenderContext context = g2.getFontRenderContext();
+ Rectangle2D bounds = f.getStringBounds(message, context);
+
+ // set (x,y) = top left corner of text
+
+ double x = (getWidth() - bounds.getWidth()) / 2;
+ double y = (getHeight() - bounds.getHeight()) / 2;
+
+ // add ascent to y to reach the baseline
+
+ double ascent = -bounds.getY();
+ double baseY = y + ascent;
+
+ // draw the message
+
+ g2.drawString(message, (int) x, (int) baseY);
+
+ g2.setPaint(Color.LIGHT_GRAY);
+
+ // draw the baseline
+
+ g2.draw(new Line2D.Double(x, baseY, x + bounds.getWidth(), baseY));
+
+ // draw the enclosing rectangle
+
+ Rectangle2D rect = new Rectangle2D.Double(x, y, bounds.getWidth(), bounds.getHeight());
+ g2.draw(rect);
+ }
+
+ public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); }
+}
diff --git a/corejava第10版/v1ch10/icon.gif b/corejava第10版/v1ch10/icon.gif
new file mode 100644
index 0000000..0e76daf
Binary files /dev/null and b/corejava第10版/v1ch10/icon.gif differ
diff --git a/javacore第11版/corejava/v1ch11/image/ImageTest.java b/corejava第10版/v1ch10/image/ImageTest.java
similarity index 100%
rename from javacore第11版/corejava/v1ch11/image/ImageTest.java
rename to corejava第10版/v1ch10/image/ImageTest.java
diff --git a/javacore第11版/corejava/v1ch10/listFonts/ListFonts.java b/corejava第10版/v1ch10/listFonts/ListFonts.java
similarity index 100%
rename from javacore第11版/corejava/v1ch10/listFonts/ListFonts.java
rename to corejava第10版/v1ch10/listFonts/ListFonts.java
diff --git a/corejava第10版/v1ch10/notHelloWorld/NotHelloWorld.java b/corejava第10版/v1ch10/notHelloWorld/NotHelloWorld.java
new file mode 100644
index 0000000..a331143
--- /dev/null
+++ b/corejava第10版/v1ch10/notHelloWorld/NotHelloWorld.java
@@ -0,0 +1,53 @@
+package notHelloWorld;
+
+import javax.swing.*;
+import java.awt.*;
+
+/**
+ * @version 1.33 2015-05-12
+ * @author Cay Horstmann
+ */
+public class NotHelloWorld
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new NotHelloWorldFrame();
+ frame.setTitle("NotHelloWorld");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * A frame that contains a message panel
+ */
+class NotHelloWorldFrame extends JFrame
+{
+ public NotHelloWorldFrame()
+ {
+ add(new NotHelloWorldComponent());
+ pack();
+ }
+}
+
+/**
+ * A component that displays a message.
+ */
+class NotHelloWorldComponent extends JComponent
+{
+ public static final int MESSAGE_X = 75;
+ public static final int MESSAGE_Y = 100;
+
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 200;
+
+ public void paintComponent(Graphics g)
+ {
+ g.drawString("Not a Hello, World program", MESSAGE_X, MESSAGE_Y);
+ }
+
+ public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); }
+}
diff --git a/corejava第10版/v1ch10/simpleFrame/SimpleFrameTest.java b/corejava第10版/v1ch10/simpleFrame/SimpleFrameTest.java
new file mode 100644
index 0000000..a131c6e
--- /dev/null
+++ b/corejava第10版/v1ch10/simpleFrame/SimpleFrameTest.java
@@ -0,0 +1,32 @@
+package simpleFrame;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.33 2015-05-12
+ * @author Cay Horstmann
+ */
+public class SimpleFrameTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ SimpleFrame frame = new SimpleFrame();
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+class SimpleFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 200;
+
+ public SimpleFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+ }
+}
diff --git a/corejava第10版/v1ch10/sizedFrame/SizedFrameTest.java b/corejava第10版/v1ch10/sizedFrame/SizedFrameTest.java
new file mode 100644
index 0000000..031f8f3
--- /dev/null
+++ b/corejava第10版/v1ch10/sizedFrame/SizedFrameTest.java
@@ -0,0 +1,45 @@
+package sizedFrame;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.34 2015-06-16
+ * @author Cay Horstmann
+ */
+public class SizedFrameTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new SizedFrame();
+ frame.setTitle("SizedFrame");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+class SizedFrame extends JFrame
+{
+ public SizedFrame()
+ {
+ // get screen dimensions
+
+ Toolkit kit = Toolkit.getDefaultToolkit();
+ Dimension screenSize = kit.getScreenSize();
+ int screenHeight = screenSize.height;
+ int screenWidth = screenSize.width;
+
+ // set frame width, height and let platform pick screen location
+
+ setSize(screenWidth / 2, screenHeight / 2);
+ setLocationByPlatform(true);
+
+ // set frame icon
+
+ Image img = new ImageIcon("icon.gif").getImage();
+ setIconImage(img);
+ }
+}
diff --git a/corejava第10版/v1ch11/action/ActionFrame.java b/corejava第10版/v1ch11/action/ActionFrame.java
new file mode 100644
index 0000000..2fb5e03
--- /dev/null
+++ b/corejava第10版/v1ch11/action/ActionFrame.java
@@ -0,0 +1,71 @@
+package action;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+/**
+ * A frame with a panel that demonstrates color change actions.
+ */
+public class ActionFrame extends JFrame
+{
+ private JPanel buttonPanel;
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 200;
+
+ public ActionFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ buttonPanel = new JPanel();
+
+ // define actions
+ Action yellowAction = new ColorAction("Yellow", new ImageIcon("yellow-ball.gif"),
+ Color.YELLOW);
+ Action blueAction = new ColorAction("Blue", new ImageIcon("blue-ball.gif"), Color.BLUE);
+ Action redAction = new ColorAction("Red", new ImageIcon("red-ball.gif"), Color.RED);
+
+ // add buttons for these actions
+ buttonPanel.add(new JButton(yellowAction));
+ buttonPanel.add(new JButton(blueAction));
+ buttonPanel.add(new JButton(redAction));
+
+ // add panel to frame
+ add(buttonPanel);
+
+ // associate the Y, B, and R keys with names
+ InputMap imap = buttonPanel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
+ imap.put(KeyStroke.getKeyStroke("ctrl Y"), "panel.yellow");
+ imap.put(KeyStroke.getKeyStroke("ctrl B"), "panel.blue");
+ imap.put(KeyStroke.getKeyStroke("ctrl R"), "panel.red");
+
+ // associate the names with actions
+ ActionMap amap = buttonPanel.getActionMap();
+ amap.put("panel.yellow", yellowAction);
+ amap.put("panel.blue", blueAction);
+ amap.put("panel.red", redAction);
+ }
+
+ public class ColorAction extends AbstractAction
+ {
+ /**
+ * Constructs a color action.
+ * @param name the name to show on the button
+ * @param icon the icon to display on the button
+ * @param c the background color
+ */
+ public ColorAction(String name, Icon icon, Color c)
+ {
+ putValue(Action.NAME, name);
+ putValue(Action.SMALL_ICON, icon);
+ putValue(Action.SHORT_DESCRIPTION, "Set panel color to " + name.toLowerCase());
+ putValue("color", c);
+ }
+
+ public void actionPerformed(ActionEvent event)
+ {
+ Color c = (Color) getValue("color");
+ buttonPanel.setBackground(c);
+ }
+ }
+}
diff --git a/corejava第10版/v1ch11/action/ActionTest.java b/corejava第10版/v1ch11/action/ActionTest.java
new file mode 100644
index 0000000..4e83485
--- /dev/null
+++ b/corejava第10版/v1ch11/action/ActionTest.java
@@ -0,0 +1,21 @@
+package action;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.34 2015-06-12
+ * @author Cay Horstmann
+ */
+public class ActionTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new ActionFrame();
+ frame.setTitle("ActionTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v1ch11/blue-ball.gif b/corejava第10版/v1ch11/blue-ball.gif
similarity index 100%
rename from javacore第11版/corejava/v1ch11/blue-ball.gif
rename to corejava第10版/v1ch11/blue-ball.gif
diff --git a/corejava第10版/v1ch11/button/ButtonFrame.java b/corejava第10版/v1ch11/button/ButtonFrame.java
new file mode 100644
index 0000000..3ca0b2d
--- /dev/null
+++ b/corejava第10版/v1ch11/button/ButtonFrame.java
@@ -0,0 +1,63 @@
+package button;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+/**
+ * A frame with a button panel
+ */
+public class ButtonFrame extends JFrame
+{
+ private JPanel buttonPanel;
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 200;
+
+ public ButtonFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ // create buttons
+ JButton yellowButton = new JButton("Yellow");
+ JButton blueButton = new JButton("Blue");
+ JButton redButton = new JButton("Red");
+
+ buttonPanel = new JPanel();
+
+ // add buttons to panel
+ buttonPanel.add(yellowButton);
+ buttonPanel.add(blueButton);
+ buttonPanel.add(redButton);
+
+ // add panel to frame
+ add(buttonPanel);
+
+ // create button actions
+ ColorAction yellowAction = new ColorAction(Color.YELLOW);
+ ColorAction blueAction = new ColorAction(Color.BLUE);
+ ColorAction redAction = new ColorAction(Color.RED);
+
+ // associate actions with buttons
+ yellowButton.addActionListener(yellowAction);
+ blueButton.addActionListener(blueAction);
+ redButton.addActionListener(redAction);
+ }
+
+ /**
+ * An action listener that sets the panel's background color.
+ */
+ private class ColorAction implements ActionListener
+ {
+ private Color backgroundColor;
+
+ public ColorAction(Color c)
+ {
+ backgroundColor = c;
+ }
+
+ public void actionPerformed(ActionEvent event)
+ {
+ buttonPanel.setBackground(backgroundColor);
+ }
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch11/button/ButtonTest.java b/corejava第10版/v1ch11/button/ButtonTest.java
new file mode 100644
index 0000000..da3943a
--- /dev/null
+++ b/corejava第10版/v1ch11/button/ButtonTest.java
@@ -0,0 +1,21 @@
+package button;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.34 2015-06-12
+ * @author Cay Horstmann
+ */
+public class ButtonTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new ButtonFrame();
+ frame.setTitle("ButtonTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch11/mouse/MouseComponent.java b/corejava第10版/v1ch11/mouse/MouseComponent.java
new file mode 100644
index 0000000..530fe59
--- /dev/null
+++ b/corejava第10版/v1ch11/mouse/MouseComponent.java
@@ -0,0 +1,123 @@
+package mouse;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import java.util.*;
+import javax.swing.*;
+
+/**
+ * A component with mouse operations for adding and removing squares.
+ */
+public class MouseComponent extends JComponent
+{
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 200;
+
+ private static final int SIDELENGTH = 10;
+ private ArrayList
squares;
+ private Rectangle2D current; // the square containing the mouse cursor
+
+ public MouseComponent()
+ {
+ squares = new ArrayList<>();
+ current = null;
+
+ addMouseListener(new MouseHandler());
+ addMouseMotionListener(new MouseMotionHandler());
+ }
+
+ public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); }
+
+ public void paintComponent(Graphics g)
+ {
+ Graphics2D g2 = (Graphics2D) g;
+
+ // draw all squares
+ for (Rectangle2D r : squares)
+ g2.draw(r);
+ }
+
+ /**
+ * Finds the first square containing a point.
+ * @param p a point
+ * @return the first square that contains p
+ */
+ public Rectangle2D find(Point2D p)
+ {
+ for (Rectangle2D r : squares)
+ {
+ if (r.contains(p)) return r;
+ }
+ return null;
+ }
+
+ /**
+ * Adds a square to the collection.
+ * @param p the center of the square
+ */
+ public void add(Point2D p)
+ {
+ double x = p.getX();
+ double y = p.getY();
+
+ current = new Rectangle2D.Double(x - SIDELENGTH / 2, y - SIDELENGTH / 2, SIDELENGTH,
+ SIDELENGTH);
+ squares.add(current);
+ repaint();
+ }
+
+ /**
+ * Removes a square from the collection.
+ * @param s the square to remove
+ */
+ public void remove(Rectangle2D s)
+ {
+ if (s == null) return;
+ if (s == current) current = null;
+ squares.remove(s);
+ repaint();
+ }
+
+ private class MouseHandler extends MouseAdapter
+ {
+ public void mousePressed(MouseEvent event)
+ {
+ // add a new square if the cursor isn't inside a square
+ current = find(event.getPoint());
+ if (current == null) add(event.getPoint());
+ }
+
+ public void mouseClicked(MouseEvent event)
+ {
+ // remove the current square if double clicked
+ current = find(event.getPoint());
+ if (current != null && event.getClickCount() >= 2) remove(current);
+ }
+ }
+
+ private class MouseMotionHandler implements MouseMotionListener
+ {
+ public void mouseMoved(MouseEvent event)
+ {
+ // set the mouse cursor to cross hairs if it is inside
+ // a rectangle
+
+ if (find(event.getPoint()) == null) setCursor(Cursor.getDefaultCursor());
+ else setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
+ }
+
+ public void mouseDragged(MouseEvent event)
+ {
+ if (current != null)
+ {
+ int x = event.getX();
+ int y = event.getY();
+
+ // drag the current rectangle to center it at (x, y)
+ current.setFrame(x - SIDELENGTH / 2, y - SIDELENGTH / 2, SIDELENGTH, SIDELENGTH);
+ repaint();
+ }
+ }
+ }
+}
diff --git a/corejava第10版/v1ch11/mouse/MouseFrame.java b/corejava第10版/v1ch11/mouse/MouseFrame.java
new file mode 100644
index 0000000..b75cfdd
--- /dev/null
+++ b/corejava第10版/v1ch11/mouse/MouseFrame.java
@@ -0,0 +1,15 @@
+package mouse;
+
+import javax.swing.*;
+
+/**
+ * A frame containing a panel for testing mouse operations
+ */
+public class MouseFrame extends JFrame
+{
+ public MouseFrame()
+ {
+ add(new MouseComponent());
+ pack();
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch11/mouse/MouseTest.java b/corejava第10版/v1ch11/mouse/MouseTest.java
new file mode 100644
index 0000000..d5d87a9
--- /dev/null
+++ b/corejava第10版/v1ch11/mouse/MouseTest.java
@@ -0,0 +1,21 @@
+package mouse;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.34 2015-06-12
+ * @author Cay Horstmann
+ */
+public class MouseTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new MouseFrame();
+ frame.setTitle("MouseTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch11/plaf/PlafFrame.java b/corejava第10版/v1ch11/plaf/PlafFrame.java
new file mode 100644
index 0000000..98e2e72
--- /dev/null
+++ b/corejava第10版/v1ch11/plaf/PlafFrame.java
@@ -0,0 +1,56 @@
+package plaf;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+import javax.swing.SwingUtilities;
+import javax.swing.UIManager;
+
+/**
+ * A frame with a button panel for changing look-and-feel
+ */
+public class PlafFrame extends JFrame
+{
+ private JPanel buttonPanel;
+
+ public PlafFrame()
+ {
+ buttonPanel = new JPanel();
+
+ UIManager.LookAndFeelInfo[] infos = UIManager.getInstalledLookAndFeels();
+ for (UIManager.LookAndFeelInfo info : infos)
+ makeButton(info.getName(), info.getClassName());
+
+ add(buttonPanel);
+ pack();
+ }
+
+ /**
+ * Makes a button to change the pluggable look-and-feel.
+ * @param name the button name
+ * @param className the name of the look-and-feel class
+ */
+ private void makeButton(String name, String className)
+ {
+ // add button to panel
+
+ JButton button = new JButton(name);
+ buttonPanel.add(button);
+
+ // set button action
+
+ button.addActionListener(event -> {
+ // button action: switch to the new look-and-feel
+ try
+ {
+ UIManager.setLookAndFeel(className);
+ SwingUtilities.updateComponentTreeUI(this);
+ pack();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ });
+ }
+}
diff --git a/corejava第10版/v1ch11/plaf/PlafTest.java b/corejava第10版/v1ch11/plaf/PlafTest.java
new file mode 100644
index 0000000..c8572b9
--- /dev/null
+++ b/corejava第10版/v1ch11/plaf/PlafTest.java
@@ -0,0 +1,21 @@
+package plaf;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.32 2015-06-12
+ * @author Cay Horstmann
+ */
+public class PlafTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new PlafFrame();
+ frame.setTitle("PlafTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v1ch10/red-ball.gif b/corejava第10版/v1ch11/red-ball.gif
similarity index 100%
rename from javacore第11版/corejava/v1ch10/red-ball.gif
rename to corejava第10版/v1ch11/red-ball.gif
diff --git a/javacore第11版/corejava/v1ch10/yellow-ball.gif b/corejava第10版/v1ch11/yellow-ball.gif
similarity index 100%
rename from javacore第11版/corejava/v1ch10/yellow-ball.gif
rename to corejava第10版/v1ch11/yellow-ball.gif
diff --git a/javacore第11版/corejava/v1ch11/ace.gif b/corejava第10版/v1ch12/ace.gif
similarity index 100%
rename from javacore第11版/corejava/v1ch11/ace.gif
rename to corejava第10版/v1ch12/ace.gif
diff --git a/javacore第11版/corejava/v2ch11/treeRender/blue-ball.gif b/corejava第10版/v1ch12/blue-ball.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/treeRender/blue-ball.gif
rename to corejava第10版/v1ch12/blue-ball.gif
diff --git a/corejava第10版/v1ch12/border/BorderFrame.java b/corejava第10版/v1ch12/border/BorderFrame.java
new file mode 100644
index 0000000..d1317e2
--- /dev/null
+++ b/corejava第10版/v1ch12/border/BorderFrame.java
@@ -0,0 +1,46 @@
+package border;
+
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.border.*;
+
+/**
+ * A frame with radio buttons to pick a border style.
+ */
+public class BorderFrame extends JFrame
+{
+ private JPanel demoPanel;
+ private JPanel buttonPanel;
+ private ButtonGroup group;
+
+ public BorderFrame()
+ {
+ demoPanel = new JPanel();
+ buttonPanel = new JPanel();
+ group = new ButtonGroup();
+
+ addRadioButton("Lowered bevel", BorderFactory.createLoweredBevelBorder());
+ addRadioButton("Raised bevel", BorderFactory.createRaisedBevelBorder());
+ addRadioButton("Etched", BorderFactory.createEtchedBorder());
+ addRadioButton("Line", BorderFactory.createLineBorder(Color.BLUE));
+ addRadioButton("Matte", BorderFactory.createMatteBorder(10, 10, 10, 10, Color.BLUE));
+ addRadioButton("Empty", BorderFactory.createEmptyBorder());
+
+ Border etched = BorderFactory.createEtchedBorder();
+ Border titled = BorderFactory.createTitledBorder(etched, "Border types");
+ buttonPanel.setBorder(titled);
+
+ setLayout(new GridLayout(2, 1));
+ add(buttonPanel);
+ add(demoPanel);
+ pack();
+ }
+
+ public void addRadioButton(String buttonName, Border b)
+ {
+ JRadioButton button = new JRadioButton(buttonName);
+ button.addActionListener(event -> demoPanel.setBorder(b));
+ group.add(button);
+ buttonPanel.add(button);
+ }
+}
diff --git a/corejava第10版/v1ch12/border/BorderTest.java b/corejava第10版/v1ch12/border/BorderTest.java
new file mode 100644
index 0000000..0c74f8d
--- /dev/null
+++ b/corejava第10版/v1ch12/border/BorderTest.java
@@ -0,0 +1,21 @@
+package border;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.34 2015-06-13
+ * @author Cay Horstmann
+ */
+public class BorderTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new BorderFrame();
+ frame.setTitle("BorderTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
diff --git a/corejava第10版/v1ch12/calculator/Calculator.java b/corejava第10版/v1ch12/calculator/Calculator.java
new file mode 100644
index 0000000..ee0d0af
--- /dev/null
+++ b/corejava第10版/v1ch12/calculator/Calculator.java
@@ -0,0 +1,21 @@
+package calculator;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.34 2015-06-12
+ * @author Cay Horstmann
+ */
+public class Calculator
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ CalculatorFrame frame = new CalculatorFrame();
+ frame.setTitle("Calculator");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
diff --git a/javacore第11版/corejava/v1ch11/calculator/CalculatorFrame.java b/corejava第10版/v1ch12/calculator/CalculatorFrame.java
similarity index 100%
rename from javacore第11版/corejava/v1ch11/calculator/CalculatorFrame.java
rename to corejava第10版/v1ch12/calculator/CalculatorFrame.java
diff --git a/corejava第10版/v1ch12/calculator/CalculatorPanel.java b/corejava第10版/v1ch12/calculator/CalculatorPanel.java
new file mode 100644
index 0000000..3475d35
--- /dev/null
+++ b/corejava第10版/v1ch12/calculator/CalculatorPanel.java
@@ -0,0 +1,132 @@
+package calculator;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+/**
+ * A panel with calculator buttons and a result display.
+ */
+public class CalculatorPanel extends JPanel
+{
+ private JButton display;
+ private JPanel panel;
+ private double result;
+ private String lastCommand;
+ private boolean start;
+
+ public CalculatorPanel()
+ {
+ setLayout(new BorderLayout());
+
+ result = 0;
+ lastCommand = "=";
+ start = true;
+
+ // add the display
+
+ display = new JButton("0");
+ display.setEnabled(false);
+ add(display, BorderLayout.NORTH);
+
+ ActionListener insert = new InsertAction();
+ ActionListener command = new CommandAction();
+
+ // add the buttons in a 4 x 4 grid
+
+ panel = new JPanel();
+ panel.setLayout(new GridLayout(4, 4));
+
+ addButton("7", insert);
+ addButton("8", insert);
+ addButton("9", insert);
+ addButton("/", command);
+
+ addButton("4", insert);
+ addButton("5", insert);
+ addButton("6", insert);
+ addButton("*", command);
+
+ addButton("1", insert);
+ addButton("2", insert);
+ addButton("3", insert);
+ addButton("-", command);
+
+ addButton("0", insert);
+ addButton(".", insert);
+ addButton("=", command);
+ addButton("+", command);
+
+ add(panel, BorderLayout.CENTER);
+ }
+
+ /**
+ * Adds a button to the center panel.
+ * @param label the button label
+ * @param listener the button listener
+ */
+ private void addButton(String label, ActionListener listener)
+ {
+ JButton button = new JButton(label);
+ button.addActionListener(listener);
+ panel.add(button);
+ }
+
+ /**
+ * This action inserts the button action string to the end of the display text.
+ */
+ private class InsertAction implements ActionListener
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ String input = event.getActionCommand();
+ if (start)
+ {
+ display.setText("");
+ start = false;
+ }
+ display.setText(display.getText() + input);
+ }
+ }
+
+ /**
+ * This action executes the command that the button action string denotes.
+ */
+ private class CommandAction implements ActionListener
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ String command = event.getActionCommand();
+
+ if (start)
+ {
+ if (command.equals("-"))
+ {
+ display.setText(command);
+ start = false;
+ }
+ else lastCommand = command;
+ }
+ else
+ {
+ calculate(Double.parseDouble(display.getText()));
+ lastCommand = command;
+ start = true;
+ }
+ }
+ }
+
+ /**
+ * Carries out the pending calculation.
+ * @param x the value to be accumulated with the prior result.
+ */
+ public void calculate(double x)
+ {
+ if (lastCommand.equals("+")) result += x;
+ else if (lastCommand.equals("-")) result -= x;
+ else if (lastCommand.equals("*")) result *= x;
+ else if (lastCommand.equals("/")) result /= x;
+ else if (lastCommand.equals("=")) result = x;
+ display.setText("" + result);
+ }
+}
diff --git a/corejava第10版/v1ch12/checkBox/CheckBoxFrame.java b/corejava第10版/v1ch12/checkBox/CheckBoxFrame.java
new file mode 100644
index 0000000..c85d48a
--- /dev/null
+++ b/corejava第10版/v1ch12/checkBox/CheckBoxFrame.java
@@ -0,0 +1,52 @@
+package checkBox;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+/**
+ * A frame with a sample text label and check boxes for selecting font
+ * attributes.
+ */
+public class CheckBoxFrame extends JFrame
+{
+ private JLabel label;
+ private JCheckBox bold;
+ private JCheckBox italic;
+ private static final int FONTSIZE = 24;
+
+ public CheckBoxFrame()
+ {
+ // add the sample text label
+
+ label = new JLabel("The quick brown fox jumps over the lazy dog.");
+ label.setFont(new Font("Serif", Font.BOLD, FONTSIZE));
+ add(label, BorderLayout.CENTER);
+
+ // this listener sets the font attribute of
+ // the label to the check box state
+
+ ActionListener listener = event -> {
+ int mode = 0;
+ if (bold.isSelected()) mode += Font.BOLD;
+ if (italic.isSelected()) mode += Font.ITALIC;
+ label.setFont(new Font("Serif", mode, FONTSIZE));
+ };
+
+ // add the check boxes
+
+ JPanel buttonPanel = new JPanel();
+
+ bold = new JCheckBox("Bold");
+ bold.addActionListener(listener);
+ bold.setSelected(true);
+ buttonPanel.add(bold);
+
+ italic = new JCheckBox("Italic");
+ italic.addActionListener(listener);
+ buttonPanel.add(italic);
+
+ add(buttonPanel, BorderLayout.SOUTH);
+ pack();
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch12/checkBox/CheckBoxTest.java b/corejava第10版/v1ch12/checkBox/CheckBoxTest.java
new file mode 100644
index 0000000..fe51b4b
--- /dev/null
+++ b/corejava第10版/v1ch12/checkBox/CheckBoxTest.java
@@ -0,0 +1,21 @@
+package checkBox;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.34 2015-06-12
+ * @author Cay Horstmann
+ */
+public class CheckBoxTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new CheckBoxFrame();
+ frame.setTitle("CheckBoxTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
diff --git a/corejava第10版/v1ch12/circleLayout/CircleLayout.java b/corejava第10版/v1ch12/circleLayout/CircleLayout.java
new file mode 100644
index 0000000..5b3e050
--- /dev/null
+++ b/corejava第10版/v1ch12/circleLayout/CircleLayout.java
@@ -0,0 +1,115 @@
+package circleLayout;
+
+import java.awt.*;
+
+/**
+ * A layout manager that lays out components along a circle.
+ */
+public class CircleLayout implements LayoutManager
+{
+ private int minWidth = 0;
+ private int minHeight = 0;
+ private int preferredWidth = 0;
+ private int preferredHeight = 0;
+ private boolean sizesSet = false;
+ private int maxComponentWidth = 0;
+ private int maxComponentHeight = 0;
+
+ public void addLayoutComponent(String name, Component comp)
+ {
+ }
+
+ public void removeLayoutComponent(Component comp)
+ {
+ }
+
+ public void setSizes(Container parent)
+ {
+ if (sizesSet) return;
+ int n = parent.getComponentCount();
+
+ preferredWidth = 0;
+ preferredHeight = 0;
+ minWidth = 0;
+ minHeight = 0;
+ maxComponentWidth = 0;
+ maxComponentHeight = 0;
+
+ // compute the maximum component widths and heights
+ // and set the preferred size to the sum of the component sizes.
+ for (int i = 0; i < n; i++)
+ {
+ Component c = parent.getComponent(i);
+ if (c.isVisible())
+ {
+ Dimension d = c.getPreferredSize();
+ maxComponentWidth = Math.max(maxComponentWidth, d.width);
+ maxComponentHeight = Math.max(maxComponentHeight, d.height);
+ preferredWidth += d.width;
+ preferredHeight += d.height;
+ }
+ }
+ minWidth = preferredWidth / 2;
+ minHeight = preferredHeight / 2;
+ sizesSet = true;
+ }
+
+ public Dimension preferredLayoutSize(Container parent)
+ {
+ setSizes(parent);
+ Insets insets = parent.getInsets();
+ int width = preferredWidth + insets.left + insets.right;
+ int height = preferredHeight + insets.top + insets.bottom;
+ return new Dimension(width, height);
+ }
+
+ public Dimension minimumLayoutSize(Container parent)
+ {
+ setSizes(parent);
+ Insets insets = parent.getInsets();
+ int width = minWidth + insets.left + insets.right;
+ int height = minHeight + insets.top + insets.bottom;
+ return new Dimension(width, height);
+ }
+
+ public void layoutContainer(Container parent)
+ {
+ setSizes(parent);
+
+ // compute center of the circle
+
+ Insets insets = parent.getInsets();
+ int containerWidth = parent.getSize().width - insets.left - insets.right;
+ int containerHeight = parent.getSize().height - insets.top - insets.bottom;
+
+ int xcenter = insets.left + containerWidth / 2;
+ int ycenter = insets.top + containerHeight / 2;
+
+ // compute radius of the circle
+
+ int xradius = (containerWidth - maxComponentWidth) / 2;
+ int yradius = (containerHeight - maxComponentHeight) / 2;
+ int radius = Math.min(xradius, yradius);
+
+ // lay out components along the circle
+
+ int n = parent.getComponentCount();
+ for (int i = 0; i < n; i++)
+ {
+ Component c = parent.getComponent(i);
+ if (c.isVisible())
+ {
+ double angle = 2 * Math.PI * i / n;
+
+ // center point of component
+ int x = xcenter + (int) (Math.cos(angle) * radius);
+ int y = ycenter + (int) (Math.sin(angle) * radius);
+
+ // move component so that its center is (x, y)
+ // and its size is its preferred size
+ Dimension d = c.getPreferredSize();
+ c.setBounds(x - d.width / 2, y - d.height / 2, d.width, d.height);
+ }
+ }
+ }
+}
diff --git a/javacore第11版/corejava/v1ch11/circleLayout/CircleLayoutFrame.java b/corejava第10版/v1ch12/circleLayout/CircleLayoutFrame.java
similarity index 100%
rename from javacore第11版/corejava/v1ch11/circleLayout/CircleLayoutFrame.java
rename to corejava第10版/v1ch12/circleLayout/CircleLayoutFrame.java
diff --git a/corejava第10版/v1ch12/circleLayout/CircleLayoutTest.java b/corejava第10版/v1ch12/circleLayout/CircleLayoutTest.java
new file mode 100644
index 0000000..91bad62
--- /dev/null
+++ b/corejava第10版/v1ch12/circleLayout/CircleLayoutTest.java
@@ -0,0 +1,21 @@
+package circleLayout;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.33 2015-06-12
+ * @author Cay Horstmann
+ */
+public class CircleLayoutTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new CircleLayoutFrame();
+ frame.setTitle("CircleLayoutTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch12/colorChooser/ColorChooserFrame.java b/corejava第10版/v1ch12/colorChooser/ColorChooserFrame.java
new file mode 100644
index 0000000..444a268
--- /dev/null
+++ b/corejava第10版/v1ch12/colorChooser/ColorChooserFrame.java
@@ -0,0 +1,22 @@
+package colorChooser;
+
+import javax.swing.*;
+
+/**
+ * A frame with a color chooser panel
+ */
+public class ColorChooserFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 200;
+
+ public ColorChooserFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ // add color chooser panel to frame
+
+ ColorChooserPanel panel = new ColorChooserPanel();
+ add(panel);
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch12/colorChooser/ColorChooserPanel.java b/corejava第10版/v1ch12/colorChooser/ColorChooserPanel.java
new file mode 100644
index 0000000..1bc6a4c
--- /dev/null
+++ b/corejava第10版/v1ch12/colorChooser/ColorChooserPanel.java
@@ -0,0 +1,98 @@
+package colorChooser;
+
+import java.awt.Color;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JColorChooser;
+import javax.swing.JDialog;
+import javax.swing.JPanel;
+
+/**
+ * A panel with buttons to pop up three types of color choosers
+ */
+public class ColorChooserPanel extends JPanel
+{
+ public ColorChooserPanel()
+ {
+ JButton modalButton = new JButton("Modal");
+ modalButton.addActionListener(new ModalListener());
+ add(modalButton);
+
+ JButton modelessButton = new JButton("Modeless");
+ modelessButton.addActionListener(new ModelessListener());
+ add(modelessButton);
+
+ JButton immediateButton = new JButton("Immediate");
+ immediateButton.addActionListener(new ImmediateListener());
+ add(immediateButton);
+ }
+
+ /**
+ * This listener pops up a modal color chooser
+ */
+ private class ModalListener implements ActionListener
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ Color defaultColor = getBackground();
+ Color selected = JColorChooser.showDialog(ColorChooserPanel.this, "Set background",
+ defaultColor);
+ if (selected != null) setBackground(selected);
+ }
+ }
+
+ /**
+ * This listener pops up a modeless color chooser. The panel color is changed when the user
+ * clicks the OK button.
+ */
+ private class ModelessListener implements ActionListener
+ {
+ private JDialog dialog;
+ private JColorChooser chooser;
+
+ public ModelessListener()
+ {
+ chooser = new JColorChooser();
+ dialog = JColorChooser.createDialog(ColorChooserPanel.this, "Background Color",
+ false /* not modal */, chooser,
+ event -> setBackground(chooser.getColor()),
+ null /* no Cancel button listener */);
+ }
+
+ public void actionPerformed(ActionEvent event)
+ {
+ chooser.setColor(getBackground());
+ dialog.setVisible(true);
+ }
+ }
+
+ /**
+ * This listener pops up a modeless color chooser. The panel color is changed immediately when
+ * the user picks a new color.
+ */
+ private class ImmediateListener implements ActionListener
+ {
+ private JDialog dialog;
+ private JColorChooser chooser;
+
+ public ImmediateListener()
+ {
+ chooser = new JColorChooser();
+ chooser.getSelectionModel().addChangeListener(
+ event -> setBackground(chooser.getColor()));
+
+ dialog = new JDialog((Frame) null, false /* not modal */);
+ dialog.add(chooser);
+ dialog.pack();
+ }
+
+ public void actionPerformed(ActionEvent event)
+ {
+ chooser.setColor(getBackground());
+ dialog.setVisible(true);
+ }
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch12/colorChooser/ColorChooserTest.java b/corejava第10版/v1ch12/colorChooser/ColorChooserTest.java
new file mode 100644
index 0000000..c46c4ae
--- /dev/null
+++ b/corejava第10版/v1ch12/colorChooser/ColorChooserTest.java
@@ -0,0 +1,21 @@
+package colorChooser;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.04 2015-06-12
+ * @author Cay Horstmann
+ */
+public class ColorChooserTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new ColorChooserFrame();
+ frame.setTitle("ColorChooserTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
diff --git a/corejava第10版/v1ch12/comboBox/ComboBoxFrame.java b/corejava第10版/v1ch12/comboBox/ComboBoxFrame.java
new file mode 100644
index 0000000..d75c271
--- /dev/null
+++ b/corejava第10版/v1ch12/comboBox/ComboBoxFrame.java
@@ -0,0 +1,51 @@
+package comboBox;
+
+import java.awt.BorderLayout;
+import java.awt.Font;
+
+import javax.swing.JComboBox;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+/**
+ * A frame with a sample text label and a combo box for selecting font faces.
+ */
+public class ComboBoxFrame extends JFrame
+{
+ private JComboBox faceCombo;
+ private JLabel label;
+ private static final int DEFAULT_SIZE = 24;
+
+ public ComboBoxFrame()
+ {
+ // add the sample text label
+
+ label = new JLabel("The quick brown fox jumps over the lazy dog.");
+ label.setFont(new Font("Serif", Font.PLAIN, DEFAULT_SIZE));
+ add(label, BorderLayout.CENTER);
+
+ // make a combo box and add face names
+
+ faceCombo = new JComboBox<>();
+ faceCombo.addItem("Serif");
+ faceCombo.addItem("SansSerif");
+ faceCombo.addItem("Monospaced");
+ faceCombo.addItem("Dialog");
+ faceCombo.addItem("DialogInput");
+
+ // the combo box listener changes the label font to the selected face name
+
+ faceCombo.addActionListener(event ->
+ label.setFont(
+ new Font(faceCombo.getItemAt(faceCombo.getSelectedIndex()),
+ Font.PLAIN, DEFAULT_SIZE)));
+
+ // add combo box to a panel at the frame's southern border
+
+ JPanel comboPanel = new JPanel();
+ comboPanel.add(faceCombo);
+ add(comboPanel, BorderLayout.SOUTH);
+ pack();
+ }
+}
diff --git a/corejava第10版/v1ch12/comboBox/ComboBoxTest.java b/corejava第10版/v1ch12/comboBox/ComboBoxTest.java
new file mode 100644
index 0000000..9482190
--- /dev/null
+++ b/corejava第10版/v1ch12/comboBox/ComboBoxTest.java
@@ -0,0 +1,21 @@
+package comboBox;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.35 2015-06-12
+ * @author Cay Horstmann
+ */
+public class ComboBoxTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new ComboBoxFrame();
+ frame.setTitle("ComboBoxTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v1ch11/copy.gif b/corejava第10版/v1ch12/copy.gif
similarity index 100%
rename from javacore第11版/corejava/v1ch11/copy.gif
rename to corejava第10版/v1ch12/copy.gif
diff --git a/javacore第11版/corejava/v1ch11/cut.gif b/corejava第10版/v1ch12/cut.gif
similarity index 100%
rename from javacore第11版/corejava/v1ch11/cut.gif
rename to corejava第10版/v1ch12/cut.gif
diff --git a/corejava第10版/v1ch12/dataExchange/DataExchangeFrame.java b/corejava第10版/v1ch12/dataExchange/DataExchangeFrame.java
new file mode 100644
index 0000000..8fc4963
--- /dev/null
+++ b/corejava第10版/v1ch12/dataExchange/DataExchangeFrame.java
@@ -0,0 +1,67 @@
+package dataExchange;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+/**
+ * A frame with a menu whose File->Connect action shows a password dialog.
+ */
+public class DataExchangeFrame extends JFrame
+{
+ public static final int TEXT_ROWS = 20;
+ public static final int TEXT_COLUMNS = 40;
+ private PasswordChooser dialog = null;
+ private JTextArea textArea;
+
+ public DataExchangeFrame()
+ {
+ // construct a File menu
+
+ JMenuBar mbar = new JMenuBar();
+ setJMenuBar(mbar);
+ JMenu fileMenu = new JMenu("File");
+ mbar.add(fileMenu);
+
+ // add Connect and Exit menu items
+
+ JMenuItem connectItem = new JMenuItem("Connect");
+ connectItem.addActionListener(new ConnectAction());
+ fileMenu.add(connectItem);
+
+ // The Exit item exits the program
+
+ JMenuItem exitItem = new JMenuItem("Exit");
+ exitItem.addActionListener(event -> System.exit(0));
+ fileMenu.add(exitItem);
+
+ textArea = new JTextArea(TEXT_ROWS, TEXT_COLUMNS);
+ add(new JScrollPane(textArea), BorderLayout.CENTER);
+ pack();
+ }
+
+ /**
+ * The Connect action pops up the password dialog.
+ */
+ private class ConnectAction implements ActionListener
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ // if first time, construct dialog
+
+ if (dialog == null) dialog = new PasswordChooser();
+
+ // set default values
+ dialog.setUser(new User("yourname", null));
+
+ // pop up dialog
+ if (dialog.showDialog(DataExchangeFrame.this, "Connect"))
+ {
+ // if accepted, retrieve user input
+ User u = dialog.getUser();
+ textArea.append("user name = " + u.getName() + ", password = "
+ + (new String(u.getPassword())) + "\n");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch12/dataExchange/DataExchangeTest.java b/corejava第10版/v1ch12/dataExchange/DataExchangeTest.java
new file mode 100644
index 0000000..db584bd
--- /dev/null
+++ b/corejava第10版/v1ch12/dataExchange/DataExchangeTest.java
@@ -0,0 +1,21 @@
+package dataExchange;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.34 2015-06-12
+ * @author Cay Horstmann
+ */
+public class DataExchangeTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new DataExchangeFrame();
+ frame.setTitle("DataExchangeTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
diff --git a/corejava第10版/v1ch12/dataExchange/PasswordChooser.java b/corejava第10版/v1ch12/dataExchange/PasswordChooser.java
new file mode 100644
index 0000000..0a37258
--- /dev/null
+++ b/corejava第10版/v1ch12/dataExchange/PasswordChooser.java
@@ -0,0 +1,111 @@
+package dataExchange;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Frame;
+import java.awt.GridLayout;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JTextField;
+import javax.swing.SwingUtilities;
+
+/**
+ * A password chooser that is shown inside a dialog
+ */
+public class PasswordChooser extends JPanel
+{
+ private JTextField username;
+ private JPasswordField password;
+ private JButton okButton;
+ private boolean ok;
+ private JDialog dialog;
+
+ public PasswordChooser()
+ {
+ setLayout(new BorderLayout());
+
+ // construct a panel with user name and password fields
+
+ JPanel panel = new JPanel();
+ panel.setLayout(new GridLayout(2, 2));
+ panel.add(new JLabel("User name:"));
+ panel.add(username = new JTextField(""));
+ panel.add(new JLabel("Password:"));
+ panel.add(password = new JPasswordField(""));
+ add(panel, BorderLayout.CENTER);
+
+ // create Ok and Cancel buttons that terminate the dialog
+
+ okButton = new JButton("Ok");
+ okButton.addActionListener(event -> {
+ ok = true;
+ dialog.setVisible(false);
+ });
+
+ JButton cancelButton = new JButton("Cancel");
+ cancelButton.addActionListener(event -> dialog.setVisible(false));
+
+ // add buttons to southern border
+
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.add(okButton);
+ buttonPanel.add(cancelButton);
+ add(buttonPanel, BorderLayout.SOUTH);
+ }
+
+ /**
+ * Sets the dialog defaults.
+ * @param u the default user information
+ */
+ public void setUser(User u)
+ {
+ username.setText(u.getName());
+ }
+
+ /**
+ * Gets the dialog entries.
+ * @return a User object whose state represents the dialog entries
+ */
+ public User getUser()
+ {
+ return new User(username.getText(), password.getPassword());
+ }
+
+ /**
+ * Show the chooser panel in a dialog
+ * @param parent a component in the owner frame or null
+ * @param title the dialog window title
+ */
+ public boolean showDialog(Component parent, String title)
+ {
+ ok = false;
+
+ // locate the owner frame
+
+ Frame owner = null;
+ if (parent instanceof Frame)
+ owner = (Frame) parent;
+ else
+ owner = (Frame) SwingUtilities.getAncestorOfClass(Frame.class, parent);
+
+ // if first time, or if owner has changed, make new dialog
+
+ if (dialog == null || dialog.getOwner() != owner)
+ {
+ dialog = new JDialog(owner, true);
+ dialog.add(this);
+ dialog.getRootPane().setDefaultButton(okButton);
+ dialog.pack();
+ }
+
+ // set title and show dialog
+
+ dialog.setTitle(title);
+ dialog.setVisible(true);
+ return ok;
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v1ch11/dataExchange/User.java b/corejava第10版/v1ch12/dataExchange/User.java
similarity index 100%
rename from javacore第11版/corejava/v1ch11/dataExchange/User.java
rename to corejava第10版/v1ch12/dataExchange/User.java
diff --git a/corejava第10版/v1ch12/dialog/AboutDialog.java b/corejava第10版/v1ch12/dialog/AboutDialog.java
new file mode 100644
index 0000000..74caafb
--- /dev/null
+++ b/corejava第10版/v1ch12/dialog/AboutDialog.java
@@ -0,0 +1,40 @@
+package dialog;
+
+import java.awt.BorderLayout;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+/**
+ * A sample modal dialog that displays a message and waits for the user to click the OK button.
+ */
+public class AboutDialog extends JDialog
+{
+ public AboutDialog(JFrame owner)
+ {
+ super(owner, "About DialogTest", true);
+
+ // add HTML label to center
+
+ add(
+ new JLabel(
+ "Core Java By Cay Horstmann"),
+ BorderLayout.CENTER);
+
+ // OK button closes the dialog
+
+ JButton ok = new JButton("OK");
+ ok.addActionListener(event -> setVisible(false));
+
+ // add OK button to southern border
+
+ JPanel panel = new JPanel();
+ panel.add(ok);
+ add(panel, BorderLayout.SOUTH);
+
+ pack();
+ }
+}
diff --git a/corejava第10版/v1ch12/dialog/DialogFrame.java b/corejava第10版/v1ch12/dialog/DialogFrame.java
new file mode 100644
index 0000000..c11d183
--- /dev/null
+++ b/corejava第10版/v1ch12/dialog/DialogFrame.java
@@ -0,0 +1,46 @@
+package dialog;
+
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+
+/**
+ * A frame with a menu whose File->About action shows a dialog.
+ */
+public class DialogFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 200;
+ private AboutDialog dialog;
+
+ public DialogFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ // Construct a File menu.
+
+ JMenuBar menuBar = new JMenuBar();
+ setJMenuBar(menuBar);
+ JMenu fileMenu = new JMenu("File");
+ menuBar.add(fileMenu);
+
+ // Add About and Exit menu items.
+
+ // The About item shows the About dialog.
+
+ JMenuItem aboutItem = new JMenuItem("About");
+ aboutItem.addActionListener(event -> {
+ if (dialog == null) // first time
+ dialog = new AboutDialog(DialogFrame.this);
+ dialog.setVisible(true); // pop up dialog
+ });
+ fileMenu.add(aboutItem);
+
+ // The Exit item exits the program.
+
+ JMenuItem exitItem = new JMenuItem("Exit");
+ exitItem.addActionListener(event -> System.exit(0));
+ fileMenu.add(exitItem);
+ }
+}
diff --git a/corejava第10版/v1ch12/dialog/DialogTest.java b/corejava第10版/v1ch12/dialog/DialogTest.java
new file mode 100644
index 0000000..54e1daa
--- /dev/null
+++ b/corejava第10版/v1ch12/dialog/DialogTest.java
@@ -0,0 +1,21 @@
+package dialog;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.34 2012-06-12
+ * @author Cay Horstmann
+ */
+public class DialogTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new DialogFrame();
+ frame.setTitle("DialogTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch12/eventTracer/EventTracer.java b/corejava第10版/v1ch12/eventTracer/EventTracer.java
new file mode 100644
index 0000000..e5021a2
--- /dev/null
+++ b/corejava第10版/v1ch12/eventTracer/EventTracer.java
@@ -0,0 +1,78 @@
+package eventTracer;
+
+import java.awt.*;
+import java.beans.*;
+import java.lang.reflect.*;
+
+/**
+ * @version 1.31 2004-05-10
+ * @author Cay Horstmann
+ */
+public class EventTracer
+{
+ private InvocationHandler handler;
+
+ public EventTracer()
+ {
+ // the handler for all event proxies
+ handler = new InvocationHandler()
+ {
+ public Object invoke(Object proxy, Method method, Object[] args)
+ {
+ System.out.println(method + ":" + args[0]);
+ return null;
+ }
+ };
+ }
+
+ /**
+ * Adds event tracers for all events to which this component and its children can listen
+ * @param c a component
+ */
+ public void add(Component c)
+ {
+ try
+ {
+ // get all events to which this component can listen
+ BeanInfo info = Introspector.getBeanInfo(c.getClass());
+
+ EventSetDescriptor[] eventSets = info.getEventSetDescriptors();
+ for (EventSetDescriptor eventSet : eventSets)
+ addListener(c, eventSet);
+ }
+ catch (IntrospectionException e)
+ {
+ }
+ // ok not to add listeners if exception is thrown
+
+ if (c instanceof Container)
+ {
+ // get all children and call add recursively
+ for (Component comp : ((Container) c).getComponents())
+ add(comp);
+ }
+ }
+
+ /**
+ * Add a listener to the given event set
+ * @param c a component
+ * @param eventSet a descriptor of a listener interface
+ */
+ public void addListener(Component c, EventSetDescriptor eventSet)
+ {
+ // make proxy object for this listener type and route all calls to the handler
+ Object proxy = Proxy.newProxyInstance(null, new Class[] { eventSet.getListenerType() },
+ handler);
+
+ // add the proxy as a listener to the component
+ Method addListenerMethod = eventSet.getAddListenerMethod();
+ try
+ {
+ addListenerMethod.invoke(c, proxy);
+ }
+ catch (ReflectiveOperationException e)
+ {
+ }
+ // ok not to add listener if exception is thrown
+ }
+}
diff --git a/corejava第10版/v1ch12/eventTracer/EventTracerTest.java b/corejava第10版/v1ch12/eventTracer/EventTracerTest.java
new file mode 100644
index 0000000..f6a5b4f
--- /dev/null
+++ b/corejava第10版/v1ch12/eventTracer/EventTracerTest.java
@@ -0,0 +1,38 @@
+package eventTracer;
+
+import java.awt.*;
+
+import javax.swing.*;
+
+/**
+ * @version 1.14 2015-08-20
+ * @author Cay Horstmann
+ */
+public class EventTracerTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new EventTracerFrame();
+ frame.setTitle("EventTracerTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+class EventTracerFrame extends JFrame
+{
+ public EventTracerFrame()
+ {
+ // add a slider and a button
+ add(new JSlider(), BorderLayout.NORTH);
+ add(new JButton("Test"), BorderLayout.SOUTH);
+
+ // trap all events of components inside the frame
+ EventTracer tracer = new EventTracer();
+ tracer.add(this);
+ pack();
+ }
+}
diff --git a/javacore第11版/corejava/v1ch11/exit.gif b/corejava第10版/v1ch12/exit.gif
similarity index 100%
rename from javacore第11版/corejava/v1ch11/exit.gif
rename to corejava第10版/v1ch12/exit.gif
diff --git a/corejava第10版/v1ch12/fileChooser/FileChooserTest.java b/corejava第10版/v1ch12/fileChooser/FileChooserTest.java
new file mode 100644
index 0000000..efbaabd
--- /dev/null
+++ b/corejava第10版/v1ch12/fileChooser/FileChooserTest.java
@@ -0,0 +1,21 @@
+package fileChooser;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.25 2015-06-12
+ * @author Cay Horstmann
+ */
+public class FileChooserTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new ImageViewerFrame();
+ frame.setTitle("FileChooserTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
diff --git a/javacore第11版/corejava/v1ch11/fileChooser/FileIconView.java b/corejava第10版/v1ch12/fileChooser/FileIconView.java
similarity index 100%
rename from javacore第11版/corejava/v1ch11/fileChooser/FileIconView.java
rename to corejava第10版/v1ch12/fileChooser/FileIconView.java
diff --git a/corejava第10版/v1ch12/fileChooser/ImagePreviewer.java b/corejava第10版/v1ch12/fileChooser/ImagePreviewer.java
new file mode 100644
index 0000000..425838a
--- /dev/null
+++ b/corejava第10版/v1ch12/fileChooser/ImagePreviewer.java
@@ -0,0 +1,46 @@
+package fileChooser;
+
+import java.awt.*;
+import java.io.*;
+
+import javax.swing.*;
+
+/**
+ * A file chooser accessory that previews images.
+ */
+public class ImagePreviewer extends JLabel
+{
+ /**
+ * Constructs an ImagePreviewer.
+ * @param chooser the file chooser whose property changes trigger an image
+ * change in this previewer
+ */
+ public ImagePreviewer(JFileChooser chooser)
+ {
+ setPreferredSize(new Dimension(100, 100));
+ setBorder(BorderFactory.createEtchedBorder());
+
+ chooser.addPropertyChangeListener(event -> {
+ if (event.getPropertyName() == JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)
+ {
+ // the user has selected a new file
+ File f = (File) event.getNewValue();
+ if (f == null)
+ {
+ setIcon(null);
+ return;
+ }
+
+ // read the image into an icon
+ ImageIcon icon = new ImageIcon(f.getPath());
+
+ // if the icon is too large to fit, scale it
+ if (icon.getIconWidth() > getWidth())
+ icon = new ImageIcon(icon.getImage().getScaledInstance(
+ getWidth(), -1, Image.SCALE_DEFAULT));
+
+ setIcon(icon);
+ }
+ });
+ }
+}
diff --git a/corejava第10版/v1ch12/fileChooser/ImageViewerFrame.java b/corejava第10版/v1ch12/fileChooser/ImageViewerFrame.java
new file mode 100644
index 0000000..5db448d
--- /dev/null
+++ b/corejava第10版/v1ch12/fileChooser/ImageViewerFrame.java
@@ -0,0 +1,68 @@
+package fileChooser;
+
+import java.io.*;
+
+import javax.swing.*;
+import javax.swing.filechooser.*;
+import javax.swing.filechooser.FileFilter;
+
+/**
+ * A frame that has a menu for loading an image and a display area for the
+ * loaded image.
+ */
+public class ImageViewerFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 400;
+ private JLabel label;
+ private JFileChooser chooser;
+
+ public ImageViewerFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ // set up menu bar
+ JMenuBar menuBar = new JMenuBar();
+ setJMenuBar(menuBar);
+
+ JMenu menu = new JMenu("File");
+ menuBar.add(menu);
+
+ JMenuItem openItem = new JMenuItem("Open");
+ menu.add(openItem);
+ openItem.addActionListener(event -> {
+ chooser.setCurrentDirectory(new File("."));
+
+ // show file chooser dialog
+ int result = chooser.showOpenDialog(ImageViewerFrame.this);
+
+ // if image file accepted, set it as icon of the label
+ if (result == JFileChooser.APPROVE_OPTION)
+ {
+ String name = chooser.getSelectedFile().getPath();
+ label.setIcon(new ImageIcon(name));
+ pack();
+ }
+ });
+
+ JMenuItem exitItem = new JMenuItem("Exit");
+ menu.add(exitItem);
+ exitItem.addActionListener(event -> System.exit(0));
+
+ // use a label to display the images
+ label = new JLabel();
+ add(label);
+
+ // set up file chooser
+ chooser = new JFileChooser();
+
+ // accept all image files ending with .jpg, .jpeg, .gif
+ FileFilter filter = new FileNameExtensionFilter(
+ "Image files", "jpg", "jpeg", "gif");
+ chooser.setFileFilter(filter);
+
+ chooser.setAccessory(new ImagePreviewer(chooser));
+
+ chooser.setFileView(new FileIconView(filter, new ImageIcon("palette.gif")));
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch12/gridbag/FontFrame.java b/corejava第10版/v1ch12/gridbag/FontFrame.java
new file mode 100644
index 0000000..5ee0dc0
--- /dev/null
+++ b/corejava第10版/v1ch12/gridbag/FontFrame.java
@@ -0,0 +1,87 @@
+package gridbag;
+
+import java.awt.Font;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionListener;
+
+import javax.swing.BorderFactory;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JTextArea;
+
+/**
+ * A frame that uses a grid bag layout to arrange font selection components.
+ */
+public class FontFrame extends JFrame
+{
+ public static final int TEXT_ROWS = 10;
+ public static final int TEXT_COLUMNS = 20;
+
+ private JComboBox face;
+ private JComboBox size;
+ private JCheckBox bold;
+ private JCheckBox italic;
+ private JTextArea sample;
+
+ public FontFrame()
+ {
+ GridBagLayout layout = new GridBagLayout();
+ setLayout(layout);
+
+ ActionListener listener = event -> updateSample();
+
+ // construct components
+
+ JLabel faceLabel = new JLabel("Face: ");
+
+ face = new JComboBox<>(new String[] { "Serif", "SansSerif", "Monospaced",
+ "Dialog", "DialogInput" });
+
+ face.addActionListener(listener);
+
+ JLabel sizeLabel = new JLabel("Size: ");
+
+ size = new JComboBox<>(new Integer[] { 8, 10, 12, 15, 18, 24, 36, 48 });
+
+ size.addActionListener(listener);
+
+ bold = new JCheckBox("Bold");
+ bold.addActionListener(listener);
+
+ italic = new JCheckBox("Italic");
+ italic.addActionListener(listener);
+
+ sample = new JTextArea(TEXT_ROWS, TEXT_COLUMNS);
+ sample.setText("The quick brown fox jumps over the lazy dog");
+ sample.setEditable(false);
+ sample.setLineWrap(true);
+ sample.setBorder(BorderFactory.createEtchedBorder());
+
+ // add components to grid, using GBC convenience class
+
+ add(faceLabel, new GBC(0, 0).setAnchor(GBC.EAST));
+ add(face, new GBC(1, 0).setFill(GBC.HORIZONTAL).setWeight(100, 0)
+ .setInsets(1));
+ add(sizeLabel, new GBC(0, 1).setAnchor(GBC.EAST));
+ add(size, new GBC(1, 1).setFill(GBC.HORIZONTAL).setWeight(100, 0)
+ .setInsets(1));
+ add(bold, new GBC(0, 2, 2, 1).setAnchor(GBC.CENTER).setWeight(100, 100));
+ add(italic, new GBC(0, 3, 2, 1).setAnchor(GBC.CENTER).setWeight(100, 100));
+ add(sample, new GBC(2, 0, 1, 4).setFill(GBC.BOTH).setWeight(100, 100));
+ pack();
+ updateSample();
+ }
+
+ public void updateSample()
+ {
+ String fontFace = (String) face.getSelectedItem();
+ int fontStyle = (bold.isSelected() ? Font.BOLD : 0)
+ + (italic.isSelected() ? Font.ITALIC : 0);
+ int fontSize = size.getItemAt(size.getSelectedIndex());
+ Font font = new Font(fontFace, fontStyle, fontSize);
+ sample.setFont(font);
+ sample.repaint();
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v1ch11/gridbag/GBC.java b/corejava第10版/v1ch12/gridbag/GBC.java
similarity index 100%
rename from javacore第11版/corejava/v1ch11/gridbag/GBC.java
rename to corejava第10版/v1ch12/gridbag/GBC.java
diff --git a/corejava第10版/v1ch12/gridbag/GridBagLayoutTest.java b/corejava第10版/v1ch12/gridbag/GridBagLayoutTest.java
new file mode 100644
index 0000000..a6daa34
--- /dev/null
+++ b/corejava第10版/v1ch12/gridbag/GridBagLayoutTest.java
@@ -0,0 +1,22 @@
+package gridbag;
+
+import java.awt.EventQueue;
+
+import javax.swing.JFrame;
+
+/**
+ * @version 1.35 2015-06-12
+ * @author Cay Horstmann
+ */
+public class GridBagLayoutTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new FontFrame();
+ frame.setTitle("GridBagLayoutTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch12/groupLayout/FontFrame.java b/corejava第10版/v1ch12/groupLayout/FontFrame.java
new file mode 100644
index 0000000..7692a4a
--- /dev/null
+++ b/corejava第10版/v1ch12/groupLayout/FontFrame.java
@@ -0,0 +1,119 @@
+package groupLayout;
+
+import java.awt.Font;
+import java.awt.event.ActionListener;
+
+import javax.swing.BorderFactory;
+import javax.swing.GroupLayout;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.LayoutStyle;
+import javax.swing.SwingConstants;
+
+/**
+ * A frame that uses a group layout to arrange font selection components.
+ */
+public class FontFrame extends JFrame
+{
+ public static final int TEXT_ROWS = 10;
+ public static final int TEXT_COLUMNS = 20;
+
+ private JComboBox face;
+ private JComboBox size;
+ private JCheckBox bold;
+ private JCheckBox italic;
+ private JScrollPane pane;
+ private JTextArea sample;
+
+ public FontFrame()
+ {
+ ActionListener listener = event -> updateSample();
+
+ // construct components
+
+ JLabel faceLabel = new JLabel("Face: ");
+
+ face = new JComboBox<>(new String[] { "Serif", "SansSerif", "Monospaced", "Dialog",
+ "DialogInput" });
+
+ face.addActionListener(listener);
+
+ JLabel sizeLabel = new JLabel("Size: ");
+
+ size = new JComboBox<>(new Integer[] { 8, 10, 12, 15, 18, 24, 36, 48 });
+
+ size.addActionListener(listener);
+
+ bold = new JCheckBox("Bold");
+ bold.addActionListener(listener);
+
+ italic = new JCheckBox("Italic");
+ italic.addActionListener(listener);
+
+ sample = new JTextArea(TEXT_ROWS, TEXT_COLUMNS);
+ sample.setText("The quick brown fox jumps over the lazy dog");
+ sample.setEditable(false);
+ sample.setLineWrap(true);
+ sample.setBorder(BorderFactory.createEtchedBorder());
+
+ pane = new JScrollPane(sample);
+
+ GroupLayout layout = new GroupLayout(getContentPane());
+ setLayout(layout);
+ layout.setHorizontalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(
+ layout.createSequentialGroup().addContainerGap().addGroup(
+ layout.createParallelGroup(GroupLayout.Alignment.LEADING).addGroup(
+ GroupLayout.Alignment.TRAILING,
+ layout.createSequentialGroup().addGroup(
+ layout.createParallelGroup(GroupLayout.Alignment.TRAILING)
+ .addComponent(faceLabel).addComponent(sizeLabel))
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(
+ layout.createParallelGroup(
+ GroupLayout.Alignment.LEADING, false)
+ .addComponent(size).addComponent(face)))
+ .addComponent(italic).addComponent(bold)).addPreferredGap(
+ LayoutStyle.ComponentPlacement.RELATED).addComponent(pane)
+ .addContainerGap()));
+
+ layout.linkSize(SwingConstants.HORIZONTAL, new java.awt.Component[] { face, size });
+
+ layout.setVerticalGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
+ .addGroup(
+ layout.createSequentialGroup().addContainerGap().addGroup(
+ layout.createParallelGroup(GroupLayout.Alignment.LEADING).addComponent(
+ pane, GroupLayout.Alignment.TRAILING).addGroup(
+ layout.createSequentialGroup().addGroup(
+ layout.createParallelGroup(GroupLayout.Alignment.BASELINE)
+ .addComponent(face).addComponent(faceLabel))
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(
+ layout.createParallelGroup(
+ GroupLayout.Alignment.BASELINE).addComponent(size)
+ .addComponent(sizeLabel)).addPreferredGap(
+ LayoutStyle.ComponentPlacement.RELATED).addComponent(
+ italic, GroupLayout.DEFAULT_SIZE,
+ GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addPreferredGap(LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(bold, GroupLayout.DEFAULT_SIZE,
+ GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
+ .addContainerGap()));
+ pack();
+ }
+
+ public void updateSample()
+ {
+ String fontFace = (String) face.getSelectedItem();
+ int fontStyle = (bold.isSelected() ? Font.BOLD : 0)
+ + (italic.isSelected() ? Font.ITALIC : 0);
+ int fontSize = size.getItemAt(size.getSelectedIndex());
+ Font font = new Font(fontFace, fontStyle, fontSize);
+ sample.setFont(font);
+ sample.repaint();
+ }
+}
diff --git a/corejava第10版/v1ch12/groupLayout/GroupLayoutTest.java b/corejava第10版/v1ch12/groupLayout/GroupLayoutTest.java
new file mode 100644
index 0000000..8c52a70
--- /dev/null
+++ b/corejava第10版/v1ch12/groupLayout/GroupLayoutTest.java
@@ -0,0 +1,22 @@
+package groupLayout;
+
+import java.awt.EventQueue;
+
+import javax.swing.JFrame;
+
+/**
+ * @version 1.01 2015-06-12
+ * @author Cay Horstmann
+ */
+public class GroupLayoutTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new FontFrame();
+ frame.setTitle("GroupLayoutTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v1ch11/jack.gif b/corejava第10版/v1ch12/jack.gif
similarity index 100%
rename from javacore第11版/corejava/v1ch11/jack.gif
rename to corejava第10版/v1ch12/jack.gif
diff --git a/javacore第11版/corejava/v1ch11/king.gif b/corejava第10版/v1ch12/king.gif
similarity index 100%
rename from javacore第11版/corejava/v1ch11/king.gif
rename to corejava第10版/v1ch12/king.gif
diff --git a/corejava第10版/v1ch12/menu/MenuFrame.java b/corejava第10版/v1ch12/menu/MenuFrame.java
new file mode 100644
index 0000000..de40f75
--- /dev/null
+++ b/corejava第10版/v1ch12/menu/MenuFrame.java
@@ -0,0 +1,146 @@
+package menu;
+
+import java.awt.event.*;
+import javax.swing.*;
+
+/**
+ * A frame with a sample menu bar.
+ */
+public class MenuFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 200;
+ private Action saveAction;
+ private Action saveAsAction;
+ private JCheckBoxMenuItem readonlyItem;
+ private JPopupMenu popup;
+
+ /**
+ * A sample action that prints the action name to System.out
+ */
+ class TestAction extends AbstractAction
+ {
+ public TestAction(String name)
+ {
+ super(name);
+ }
+
+ public void actionPerformed(ActionEvent event)
+ {
+ System.out.println(getValue(Action.NAME) + " selected.");
+ }
+ }
+
+ public MenuFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ JMenu fileMenu = new JMenu("File");
+ fileMenu.add(new TestAction("New"));
+
+ // demonstrate accelerators
+
+ JMenuItem openItem = fileMenu.add(new TestAction("Open"));
+ openItem.setAccelerator(KeyStroke.getKeyStroke("ctrl O"));
+
+ fileMenu.addSeparator();
+
+ saveAction = new TestAction("Save");
+ JMenuItem saveItem = fileMenu.add(saveAction);
+ saveItem.setAccelerator(KeyStroke.getKeyStroke("ctrl S"));
+
+ saveAsAction = new TestAction("Save As");
+ fileMenu.add(saveAsAction);
+ fileMenu.addSeparator();
+
+ fileMenu.add(new AbstractAction("Exit")
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ System.exit(0);
+ }
+ });
+
+ // demonstrate checkbox and radio button menus
+
+ readonlyItem = new JCheckBoxMenuItem("Read-only");
+ readonlyItem.addActionListener(new ActionListener()
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ boolean saveOk = !readonlyItem.isSelected();
+ saveAction.setEnabled(saveOk);
+ saveAsAction.setEnabled(saveOk);
+ }
+ });
+
+ ButtonGroup group = new ButtonGroup();
+
+ JRadioButtonMenuItem insertItem = new JRadioButtonMenuItem("Insert");
+ insertItem.setSelected(true);
+ JRadioButtonMenuItem overtypeItem = new JRadioButtonMenuItem("Overtype");
+
+ group.add(insertItem);
+ group.add(overtypeItem);
+
+ // demonstrate icons
+
+ Action cutAction = new TestAction("Cut");
+ cutAction.putValue(Action.SMALL_ICON, new ImageIcon("cut.gif"));
+ Action copyAction = new TestAction("Copy");
+ copyAction.putValue(Action.SMALL_ICON, new ImageIcon("copy.gif"));
+ Action pasteAction = new TestAction("Paste");
+ pasteAction.putValue(Action.SMALL_ICON, new ImageIcon("paste.gif"));
+
+ JMenu editMenu = new JMenu("Edit");
+ editMenu.add(cutAction);
+ editMenu.add(copyAction);
+ editMenu.add(pasteAction);
+
+ // demonstrate nested menus
+
+ JMenu optionMenu = new JMenu("Options");
+
+ optionMenu.add(readonlyItem);
+ optionMenu.addSeparator();
+ optionMenu.add(insertItem);
+ optionMenu.add(overtypeItem);
+
+ editMenu.addSeparator();
+ editMenu.add(optionMenu);
+
+ // demonstrate mnemonics
+
+ JMenu helpMenu = new JMenu("Help");
+ helpMenu.setMnemonic('H');
+
+ JMenuItem indexItem = new JMenuItem("Index");
+ indexItem.setMnemonic('I');
+ helpMenu.add(indexItem);
+
+ // you can also add the mnemonic key to an action
+ Action aboutAction = new TestAction("About");
+ aboutAction.putValue(Action.MNEMONIC_KEY, new Integer('A'));
+ helpMenu.add(aboutAction);
+
+ // add all top-level menus to menu bar
+
+ JMenuBar menuBar = new JMenuBar();
+ setJMenuBar(menuBar);
+
+ menuBar.add(fileMenu);
+ menuBar.add(editMenu);
+ menuBar.add(helpMenu);
+
+ // demonstrate pop-ups
+
+ popup = new JPopupMenu();
+ popup.add(cutAction);
+ popup.add(copyAction);
+ popup.add(pasteAction);
+
+ JPanel panel = new JPanel();
+ panel.setComponentPopupMenu(popup);
+ add(panel);
+ }
+}
diff --git a/corejava第10版/v1ch12/menu/MenuTest.java b/corejava第10版/v1ch12/menu/MenuTest.java
new file mode 100644
index 0000000..6a05663
--- /dev/null
+++ b/corejava第10版/v1ch12/menu/MenuTest.java
@@ -0,0 +1,21 @@
+package menu;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.24 2012-06-12
+ * @author Cay Horstmann
+ */
+public class MenuTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new MenuFrame();
+ frame.setTitle("MenuTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v1ch11/nine.gif b/corejava第10版/v1ch12/nine.gif
similarity index 100%
rename from javacore第11版/corejava/v1ch11/nine.gif
rename to corejava第10版/v1ch12/nine.gif
diff --git a/corejava第10版/v1ch12/optionDialog/ButtonPanel.java b/corejava第10版/v1ch12/optionDialog/ButtonPanel.java
new file mode 100644
index 0000000..4e11bbb
--- /dev/null
+++ b/corejava第10版/v1ch12/optionDialog/ButtonPanel.java
@@ -0,0 +1,43 @@
+package optionDialog;
+
+import javax.swing.*;
+
+/**
+ * A panel with radio buttons inside a titled border.
+ */
+public class ButtonPanel extends JPanel
+{
+ private ButtonGroup group;
+
+ /**
+ * Constructs a button panel.
+ * @param title the title shown in the border
+ * @param options an array of radio button labels
+ */
+ public ButtonPanel(String title, String... options)
+ {
+ setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), title));
+ setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
+ group = new ButtonGroup();
+
+ // make one radio button for each option
+ for (String option : options)
+ {
+ JRadioButton b = new JRadioButton(option);
+ b.setActionCommand(option);
+ add(b);
+ group.add(b);
+ b.setSelected(option == options[0]);
+ }
+ }
+
+ /**
+ * Gets the currently selected option.
+ * @return the label of the currently selected radio button.
+ */
+ public String getSelection()
+ {
+ return group.getSelection().getActionCommand();
+ }
+}
+
diff --git a/corejava第10版/v1ch12/optionDialog/OptionDialogFrame.java b/corejava第10版/v1ch12/optionDialog/OptionDialogFrame.java
new file mode 100644
index 0000000..dc5375f
--- /dev/null
+++ b/corejava第10版/v1ch12/optionDialog/OptionDialogFrame.java
@@ -0,0 +1,156 @@
+package optionDialog;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import java.util.*;
+import javax.swing.*;
+
+/**
+ * A frame that contains settings for selecting various option dialogs.
+ */
+public class OptionDialogFrame extends JFrame
+{
+ private ButtonPanel typePanel;
+ private ButtonPanel messagePanel;
+ private ButtonPanel messageTypePanel;
+ private ButtonPanel optionTypePanel;
+ private ButtonPanel optionsPanel;
+ private ButtonPanel inputPanel;
+ private String messageString = "Message";
+ private Icon messageIcon = new ImageIcon("blue-ball.gif");
+ private Object messageObject = new Date();
+ private Component messageComponent = new SampleComponent();
+
+ public OptionDialogFrame()
+ {
+ JPanel gridPanel = new JPanel();
+ gridPanel.setLayout(new GridLayout(2, 3));
+
+ typePanel = new ButtonPanel("Type", "Message", "Confirm", "Option", "Input");
+ messageTypePanel = new ButtonPanel("Message Type", "ERROR_MESSAGE", "INFORMATION_MESSAGE",
+ "WARNING_MESSAGE", "QUESTION_MESSAGE", "PLAIN_MESSAGE");
+ messagePanel = new ButtonPanel("Message", "String", "Icon", "Component", "Other",
+ "Object[]");
+ optionTypePanel = new ButtonPanel("Confirm", "DEFAULT_OPTION", "YES_NO_OPTION",
+ "YES_NO_CANCEL_OPTION", "OK_CANCEL_OPTION");
+ optionsPanel = new ButtonPanel("Option", "String[]", "Icon[]", "Object[]");
+ inputPanel = new ButtonPanel("Input", "Text field", "Combo box");
+
+ gridPanel.add(typePanel);
+ gridPanel.add(messageTypePanel);
+ gridPanel.add(messagePanel);
+ gridPanel.add(optionTypePanel);
+ gridPanel.add(optionsPanel);
+ gridPanel.add(inputPanel);
+
+ // add a panel with a Show button
+
+ JPanel showPanel = new JPanel();
+ JButton showButton = new JButton("Show");
+ showButton.addActionListener(new ShowAction());
+ showPanel.add(showButton);
+
+ add(gridPanel, BorderLayout.CENTER);
+ add(showPanel, BorderLayout.SOUTH);
+ pack();
+ }
+
+ /**
+ * Gets the currently selected message.
+ * @return a string, icon, component, or object array, depending on the Message panel selection
+ */
+ public Object getMessage()
+ {
+ String s = messagePanel.getSelection();
+ if (s.equals("String")) return messageString;
+ else if (s.equals("Icon")) return messageIcon;
+ else if (s.equals("Component")) return messageComponent;
+ else if (s.equals("Object[]")) return new Object[] { messageString, messageIcon,
+ messageComponent, messageObject };
+ else if (s.equals("Other")) return messageObject;
+ else return null;
+ }
+
+ /**
+ * Gets the currently selected options.
+ * @return an array of strings, icons, or objects, depending on the Option panel selection
+ */
+ public Object[] getOptions()
+ {
+ String s = optionsPanel.getSelection();
+ if (s.equals("String[]")) return new String[] { "Yellow", "Blue", "Red" };
+ else if (s.equals("Icon[]")) return new Icon[] { new ImageIcon("yellow-ball.gif"),
+ new ImageIcon("blue-ball.gif"), new ImageIcon("red-ball.gif") };
+ else if (s.equals("Object[]")) return new Object[] { messageString, messageIcon,
+ messageComponent, messageObject };
+ else return null;
+ }
+
+ /**
+ * Gets the selected message or option type
+ * @param panel the Message Type or Confirm panel
+ * @return the selected XXX_MESSAGE or XXX_OPTION constant from the JOptionPane class
+ */
+ public int getType(ButtonPanel panel)
+ {
+ String s = panel.getSelection();
+ try
+ {
+ return JOptionPane.class.getField(s).getInt(null);
+ }
+ catch (Exception e)
+ {
+ return -1;
+ }
+ }
+
+ /**
+ * The action listener for the Show button shows a Confirm, Input, Message, or Option dialog
+ * depending on the Type panel selection.
+ */
+ private class ShowAction implements ActionListener
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ if (typePanel.getSelection().equals("Confirm")) JOptionPane.showConfirmDialog(
+ OptionDialogFrame.this, getMessage(), "Title", getType(optionTypePanel),
+ getType(messageTypePanel));
+ else if (typePanel.getSelection().equals("Input"))
+ {
+ if (inputPanel.getSelection().equals("Text field")) JOptionPane.showInputDialog(
+ OptionDialogFrame.this, getMessage(), "Title", getType(messageTypePanel));
+ else JOptionPane.showInputDialog(OptionDialogFrame.this, getMessage(), "Title",
+ getType(messageTypePanel), null, new String[] { "Yellow", "Blue", "Red" },
+ "Blue");
+ }
+ else if (typePanel.getSelection().equals("Message")) JOptionPane.showMessageDialog(
+ OptionDialogFrame.this, getMessage(), "Title", getType(messageTypePanel));
+ else if (typePanel.getSelection().equals("Option")) JOptionPane.showOptionDialog(
+ OptionDialogFrame.this, getMessage(), "Title", getType(optionTypePanel),
+ getType(messageTypePanel), null, getOptions(), getOptions()[0]);
+ }
+ }
+}
+
+/**
+ * A component with a painted surface
+ */
+
+class SampleComponent extends JComponent
+{
+ public void paintComponent(Graphics g)
+ {
+ Graphics2D g2 = (Graphics2D) g;
+ Rectangle2D rect = new Rectangle2D.Double(0, 0, getWidth() - 1, getHeight() - 1);
+ g2.setPaint(Color.YELLOW);
+ g2.fill(rect);
+ g2.setPaint(Color.BLUE);
+ g2.draw(rect);
+ }
+
+ public Dimension getPreferredSize()
+ {
+ return new Dimension(10, 10);
+ }
+}
diff --git a/corejava第10版/v1ch12/optionDialog/OptionDialogTest.java b/corejava第10版/v1ch12/optionDialog/OptionDialogTest.java
new file mode 100644
index 0000000..660e536
--- /dev/null
+++ b/corejava第10版/v1ch12/optionDialog/OptionDialogTest.java
@@ -0,0 +1,21 @@
+package optionDialog;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.34 2015-06-12
+ * @author Cay Horstmann
+ */
+public class OptionDialogTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new OptionDialogFrame();
+ frame.setTitle("OptionDialogTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
diff --git a/javacore第11版/corejava/v1ch11/palette.gif b/corejava第10版/v1ch12/palette.gif
similarity index 100%
rename from javacore第11版/corejava/v1ch11/palette.gif
rename to corejava第10版/v1ch12/palette.gif
diff --git a/javacore第11版/corejava/v1ch11/paste.gif b/corejava第10版/v1ch12/paste.gif
similarity index 100%
rename from javacore第11版/corejava/v1ch11/paste.gif
rename to corejava第10版/v1ch12/paste.gif
diff --git a/javacore第11版/corejava/v1ch11/queen.gif b/corejava第10版/v1ch12/queen.gif
similarity index 100%
rename from javacore第11版/corejava/v1ch11/queen.gif
rename to corejava第10版/v1ch12/queen.gif
diff --git a/corejava第10版/v1ch12/radioButton/RadioButtonFrame.java b/corejava第10版/v1ch12/radioButton/RadioButtonFrame.java
new file mode 100644
index 0000000..5a3e068
--- /dev/null
+++ b/corejava第10版/v1ch12/radioButton/RadioButtonFrame.java
@@ -0,0 +1,57 @@
+package radioButton;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+/**
+ * A frame with a sample text label and radio buttons for selecting font sizes.
+ */
+public class RadioButtonFrame extends JFrame
+{
+ private JPanel buttonPanel;
+ private ButtonGroup group;
+ private JLabel label;
+ private static final int DEFAULT_SIZE = 36;
+
+ public RadioButtonFrame()
+ {
+ // add the sample text label
+
+ label = new JLabel("The quick brown fox jumps over the lazy dog.");
+ label.setFont(new Font("Serif", Font.PLAIN, DEFAULT_SIZE));
+ add(label, BorderLayout.CENTER);
+
+ // add the radio buttons
+
+ buttonPanel = new JPanel();
+ group = new ButtonGroup();
+
+ addRadioButton("Small", 8);
+ addRadioButton("Medium", 12);
+ addRadioButton("Large", 18);
+ addRadioButton("Extra large", 36);
+
+ add(buttonPanel, BorderLayout.SOUTH);
+ pack();
+ }
+
+ /**
+ * Adds a radio button that sets the font size of the sample text.
+ * @param name the string to appear on the button
+ * @param size the font size that this button sets
+ */
+ public void addRadioButton(String name, int size)
+ {
+ boolean selected = size == DEFAULT_SIZE;
+ JRadioButton button = new JRadioButton(name, selected);
+ group.add(button);
+ buttonPanel.add(button);
+
+ // this listener sets the label font size
+
+ ActionListener listener = event -> label.setFont(new Font("Serif", Font.PLAIN, size));
+
+ button.addActionListener(listener);
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch12/radioButton/RadioButtonTest.java b/corejava第10版/v1ch12/radioButton/RadioButtonTest.java
new file mode 100644
index 0000000..3b642f5
--- /dev/null
+++ b/corejava第10版/v1ch12/radioButton/RadioButtonTest.java
@@ -0,0 +1,21 @@
+package radioButton;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.34 2015-06-12
+ * @author Cay Horstmann
+ */
+public class RadioButtonTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new RadioButtonFrame();
+ frame.setTitle("RadioButtonTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v1ch11/red-ball.gif b/corejava第10版/v1ch12/red-ball.gif
similarity index 100%
rename from javacore第11版/corejava/v1ch11/red-ball.gif
rename to corejava第10版/v1ch12/red-ball.gif
diff --git a/corejava第10版/v1ch12/robot/ButtonFrame.java b/corejava第10版/v1ch12/robot/ButtonFrame.java
new file mode 100644
index 0000000..8c609ca
--- /dev/null
+++ b/corejava第10版/v1ch12/robot/ButtonFrame.java
@@ -0,0 +1,63 @@
+package robot;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+/**
+ * A frame with a button panel
+ */
+public class ButtonFrame extends JFrame
+{
+ private JPanel buttonPanel;
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 200;
+
+ public ButtonFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ // create buttons
+ JButton yellowButton = new JButton("Yellow");
+ JButton blueButton = new JButton("Blue");
+ JButton redButton = new JButton("Red");
+
+ buttonPanel = new JPanel();
+
+ // add buttons to panel
+ buttonPanel.add(yellowButton);
+ buttonPanel.add(blueButton);
+ buttonPanel.add(redButton);
+
+ // add panel to frame
+ add(buttonPanel);
+
+ // create button actions
+ ColorAction yellowAction = new ColorAction(Color.YELLOW);
+ ColorAction blueAction = new ColorAction(Color.BLUE);
+ ColorAction redAction = new ColorAction(Color.RED);
+
+ // associate actions with buttons
+ yellowButton.addActionListener(yellowAction);
+ blueButton.addActionListener(blueAction);
+ redButton.addActionListener(redAction);
+ }
+
+ /**
+ * An action listener that sets the panel's background color.
+ */
+ private class ColorAction implements ActionListener
+ {
+ private Color backgroundColor;
+
+ public ColorAction(Color c)
+ {
+ backgroundColor = c;
+ }
+
+ public void actionPerformed(ActionEvent event)
+ {
+ buttonPanel.setBackground(backgroundColor);
+ }
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch12/robot/RobotTest.java b/corejava第10版/v1ch12/robot/RobotTest.java
new file mode 100644
index 0000000..09884e6
--- /dev/null
+++ b/corejava第10版/v1ch12/robot/RobotTest.java
@@ -0,0 +1,100 @@
+package robot;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.image.*;
+import javax.swing.*;
+
+/**
+ * @version 1.05 2015-08-20
+ * @author Cay Horstmann
+ */
+public class RobotTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ // make frame with a button panel
+
+ ButtonFrame frame = new ButtonFrame();
+ frame.setTitle("ButtonTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+
+ // attach a robot to the screen device
+
+ GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ GraphicsDevice screen = environment.getDefaultScreenDevice();
+
+ try
+ {
+ final Robot robot = new Robot(screen);
+ robot.waitForIdle();
+ new Thread()
+ {
+ public void run()
+ {
+ runTest(robot);
+ };
+ }.start();
+ }
+ catch (AWTException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Runs a sample test procedure
+ * @param robot the robot attached to the screen device
+ */
+ public static void runTest(Robot robot)
+ {
+ // simulate a space bar press
+ robot.keyPress(' ');
+ robot.keyRelease(' ');
+
+ // simulate a tab key followed by a space
+ robot.delay(2000);
+ robot.keyPress(KeyEvent.VK_TAB);
+ robot.keyRelease(KeyEvent.VK_TAB);
+ robot.keyPress(' ');
+ robot.keyRelease(' ');
+
+ // simulate a mouse click over the rightmost button
+ robot.delay(2000);
+ robot.mouseMove(220, 40);
+ robot.mousePress(InputEvent.BUTTON1_MASK);
+ robot.mouseRelease(InputEvent.BUTTON1_MASK);
+
+ // capture the screen and show the resulting image
+ robot.delay(2000);
+ BufferedImage image = robot.createScreenCapture(new Rectangle(0, 0, 400, 300));
+
+ ImageFrame frame = new ImageFrame(image);
+ frame.setVisible(true);
+ }
+}
+
+/**
+ * A frame to display a captured image
+ */
+class ImageFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 450;
+ private static final int DEFAULT_HEIGHT = 350;
+
+ /**
+ * @param image the image to display
+ */
+ public ImageFrame(Image image)
+ {
+ setTitle("Capture");
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ JLabel label = new JLabel(new ImageIcon(image));
+ add(label);
+ }
+}
diff --git a/corejava第10版/v1ch12/slider/SliderFrame.java b/corejava第10版/v1ch12/slider/SliderFrame.java
new file mode 100644
index 0000000..4891825
--- /dev/null
+++ b/corejava第10版/v1ch12/slider/SliderFrame.java
@@ -0,0 +1,145 @@
+package slider;
+
+import java.awt.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+
+/**
+ * A frame with many sliders and a text field to show slider values.
+ */
+public class SliderFrame extends JFrame
+{
+ private JPanel sliderPanel;
+ private JTextField textField;
+ private ChangeListener listener;
+
+ public SliderFrame()
+ {
+ sliderPanel = new JPanel();
+ sliderPanel.setLayout(new GridBagLayout());
+
+ // common listener for all sliders
+ listener = event -> {
+ // update text field when the slider value changes
+ JSlider source = (JSlider) event.getSource();
+ textField.setText("" + source.getValue());
+ };
+
+ // add a plain slider
+
+ JSlider slider = new JSlider();
+ addSlider(slider, "Plain");
+
+ // add a slider with major and minor ticks
+
+ slider = new JSlider();
+ slider.setPaintTicks(true);
+ slider.setMajorTickSpacing(20);
+ slider.setMinorTickSpacing(5);
+ addSlider(slider, "Ticks");
+
+ // add a slider that snaps to ticks
+
+ slider = new JSlider();
+ slider.setPaintTicks(true);
+ slider.setSnapToTicks(true);
+ slider.setMajorTickSpacing(20);
+ slider.setMinorTickSpacing(5);
+ addSlider(slider, "Snap to ticks");
+
+ // add a slider with no track
+
+ slider = new JSlider();
+ slider.setPaintTicks(true);
+ slider.setMajorTickSpacing(20);
+ slider.setMinorTickSpacing(5);
+ slider.setPaintTrack(false);
+ addSlider(slider, "No track");
+
+ // add an inverted slider
+
+ slider = new JSlider();
+ slider.setPaintTicks(true);
+ slider.setMajorTickSpacing(20);
+ slider.setMinorTickSpacing(5);
+ slider.setInverted(true);
+ addSlider(slider, "Inverted");
+
+ // add a slider with numeric labels
+
+ slider = new JSlider();
+ slider.setPaintTicks(true);
+ slider.setPaintLabels(true);
+ slider.setMajorTickSpacing(20);
+ slider.setMinorTickSpacing(5);
+ addSlider(slider, "Labels");
+
+ // add a slider with alphabetic labels
+
+ slider = new JSlider();
+ slider.setPaintLabels(true);
+ slider.setPaintTicks(true);
+ slider.setMajorTickSpacing(20);
+ slider.setMinorTickSpacing(5);
+
+ Dictionary labelTable = new Hashtable<>();
+ labelTable.put(0, new JLabel("A"));
+ labelTable.put(20, new JLabel("B"));
+ labelTable.put(40, new JLabel("C"));
+ labelTable.put(60, new JLabel("D"));
+ labelTable.put(80, new JLabel("E"));
+ labelTable.put(100, new JLabel("F"));
+
+ slider.setLabelTable(labelTable);
+ addSlider(slider, "Custom labels");
+
+ // add a slider with icon labels
+
+ slider = new JSlider();
+ slider.setPaintTicks(true);
+ slider.setPaintLabels(true);
+ slider.setSnapToTicks(true);
+ slider.setMajorTickSpacing(20);
+ slider.setMinorTickSpacing(20);
+
+ labelTable = new Hashtable();
+
+ // add card images
+
+ labelTable.put(0, new JLabel(new ImageIcon("nine.gif")));
+ labelTable.put(20, new JLabel(new ImageIcon("ten.gif")));
+ labelTable.put(40, new JLabel(new ImageIcon("jack.gif")));
+ labelTable.put(60, new JLabel(new ImageIcon("queen.gif")));
+ labelTable.put(80, new JLabel(new ImageIcon("king.gif")));
+ labelTable.put(100, new JLabel(new ImageIcon("ace.gif")));
+
+ slider.setLabelTable(labelTable);
+ addSlider(slider, "Icon labels");
+
+ // add the text field that displays the slider value
+
+ textField = new JTextField();
+ add(sliderPanel, BorderLayout.CENTER);
+ add(textField, BorderLayout.SOUTH);
+ pack();
+ }
+
+ /**
+ * Adds a slider to the slider panel and hooks up the listener
+ * @param s the slider
+ * @param description the slider description
+ */
+ public void addSlider(JSlider s, String description)
+ {
+ s.addChangeListener(listener);
+ JPanel panel = new JPanel();
+ panel.add(s);
+ panel.add(new JLabel(description));
+ panel.setAlignmentX(Component.LEFT_ALIGNMENT);
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.gridy = sliderPanel.getComponentCount();
+ gbc.anchor = GridBagConstraints.WEST;
+ sliderPanel.add(panel, gbc);
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch12/slider/SliderTest.java b/corejava第10版/v1ch12/slider/SliderTest.java
new file mode 100644
index 0000000..2a15f69
--- /dev/null
+++ b/corejava第10版/v1ch12/slider/SliderTest.java
@@ -0,0 +1,21 @@
+package slider;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.15 2015-06-12
+ * @author Cay Horstmann
+ */
+public class SliderTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ SliderFrame frame = new SliderFrame();
+ frame.setTitle("SliderTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v1ch11/ten.gif b/corejava第10版/v1ch12/ten.gif
similarity index 100%
rename from javacore第11版/corejava/v1ch11/ten.gif
rename to corejava第10版/v1ch12/ten.gif
diff --git a/corejava第10版/v1ch12/text/TextComponentFrame.java b/corejava第10版/v1ch12/text/TextComponentFrame.java
new file mode 100644
index 0000000..740aabf
--- /dev/null
+++ b/corejava第10版/v1ch12/text/TextComponentFrame.java
@@ -0,0 +1,56 @@
+package text;
+
+import java.awt.BorderLayout;
+import java.awt.GridLayout;
+
+import javax.swing.JButton;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JPasswordField;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JTextField;
+import javax.swing.SwingConstants;
+
+/**
+ * A frame with sample text components.
+ */
+public class TextComponentFrame extends JFrame
+{
+ public static final int TEXTAREA_ROWS = 8;
+ public static final int TEXTAREA_COLUMNS = 20;
+
+ public TextComponentFrame()
+ {
+ JTextField textField = new JTextField();
+ JPasswordField passwordField = new JPasswordField();
+
+ JPanel northPanel = new JPanel();
+ northPanel.setLayout(new GridLayout(2, 2));
+ northPanel.add(new JLabel("User name: ", SwingConstants.RIGHT));
+ northPanel.add(textField);
+ northPanel.add(new JLabel("Password: ", SwingConstants.RIGHT));
+ northPanel.add(passwordField);
+
+ add(northPanel, BorderLayout.NORTH);
+
+ JTextArea textArea = new JTextArea(TEXTAREA_ROWS, TEXTAREA_COLUMNS);
+ JScrollPane scrollPane = new JScrollPane(textArea);
+
+ add(scrollPane, BorderLayout.CENTER);
+
+ // add button to append text into the text area
+
+ JPanel southPanel = new JPanel();
+
+ JButton insertButton = new JButton("Insert");
+ southPanel.add(insertButton);
+ insertButton.addActionListener(event ->
+ textArea.append("User name: " + textField.getText() + " Password: "
+ + new String(passwordField.getPassword()) + "\n"));
+
+ add(southPanel, BorderLayout.SOUTH);
+ pack();
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch12/text/TextComponentTest.java b/corejava第10版/v1ch12/text/TextComponentTest.java
new file mode 100644
index 0000000..0a18b9e
--- /dev/null
+++ b/corejava第10版/v1ch12/text/TextComponentTest.java
@@ -0,0 +1,21 @@
+package text;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.41 2015-06-12
+ * @author Cay Horstmann
+ */
+public class TextComponentTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new TextComponentFrame();
+ frame.setTitle("TextComponentTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
diff --git a/corejava第10版/v1ch12/toolBar/ToolBarFrame.java b/corejava第10版/v1ch12/toolBar/ToolBarFrame.java
new file mode 100644
index 0000000..db9b7ba
--- /dev/null
+++ b/corejava第10版/v1ch12/toolBar/ToolBarFrame.java
@@ -0,0 +1,82 @@
+package toolBar;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+/**
+ * A frame with a toolbar and menu for color changes.
+ */
+public class ToolBarFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 200;
+ private JPanel panel;
+
+ public ToolBarFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ // add a panel for color change
+
+ panel = new JPanel();
+ add(panel, BorderLayout.CENTER);
+
+ // set up actions
+
+ Action blueAction = new ColorAction("Blue", new ImageIcon("blue-ball.gif"), Color.BLUE);
+ Action yellowAction = new ColorAction("Yellow", new ImageIcon("yellow-ball.gif"),
+ Color.YELLOW);
+ Action redAction = new ColorAction("Red", new ImageIcon("red-ball.gif"), Color.RED);
+
+ Action exitAction = new AbstractAction("Exit", new ImageIcon("exit.gif"))
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ System.exit(0);
+ }
+ };
+ exitAction.putValue(Action.SHORT_DESCRIPTION, "Exit");
+
+ // populate toolbar
+
+ JToolBar bar = new JToolBar();
+ bar.add(blueAction);
+ bar.add(yellowAction);
+ bar.add(redAction);
+ bar.addSeparator();
+ bar.add(exitAction);
+ add(bar, BorderLayout.NORTH);
+
+ // populate menu
+
+ JMenu menu = new JMenu("Color");
+ menu.add(yellowAction);
+ menu.add(blueAction);
+ menu.add(redAction);
+ menu.add(exitAction);
+ JMenuBar menuBar = new JMenuBar();
+ menuBar.add(menu);
+ setJMenuBar(menuBar);
+ }
+
+ /**
+ * The color action sets the background of the frame to a given color.
+ */
+ class ColorAction extends AbstractAction
+ {
+ public ColorAction(String name, Icon icon, Color c)
+ {
+ putValue(Action.NAME, name);
+ putValue(Action.SMALL_ICON, icon);
+ putValue(Action.SHORT_DESCRIPTION, name + " background");
+ putValue("Color", c);
+ }
+
+ public void actionPerformed(ActionEvent event)
+ {
+ Color c = (Color) getValue("Color");
+ panel.setBackground(c);
+ }
+ }
+}
diff --git a/corejava第10版/v1ch12/toolBar/ToolBarTest.java b/corejava第10版/v1ch12/toolBar/ToolBarTest.java
new file mode 100644
index 0000000..9accbeb
--- /dev/null
+++ b/corejava第10版/v1ch12/toolBar/ToolBarTest.java
@@ -0,0 +1,21 @@
+package toolBar;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.14 2015-06-12
+ * @author Cay Horstmann
+ */
+public class ToolBarTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ ToolBarFrame frame = new ToolBarFrame();
+ frame.setTitle("ToolBarTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v1ch11/yellow-ball.gif b/corejava第10版/v1ch12/yellow-ball.gif
similarity index 100%
rename from javacore第11版/corejava/v1ch11/yellow-ball.gif
rename to corejava第10版/v1ch12/yellow-ball.gif
diff --git a/javacore第11版/corejava/v1ch06/META-INF/services/serviceLoader.Cipher b/corejava第10版/v1ch13/META-INF/services/serviceLoader.Cipher
similarity index 100%
rename from javacore第11版/corejava/v1ch06/META-INF/services/serviceLoader.Cipher
rename to corejava第10版/v1ch13/META-INF/services/serviceLoader.Cipher
diff --git a/corejava第10版/v1ch13/NotHelloWorldApplet.html b/corejava第10版/v1ch13/NotHelloWorldApplet.html
new file mode 100644
index 0000000..6cbcd47
--- /dev/null
+++ b/corejava第10版/v1ch13/NotHelloWorldApplet.html
@@ -0,0 +1,3 @@
+
+
diff --git a/corejava第10版/v1ch13/ResourceTest.jar b/corejava第10版/v1ch13/ResourceTest.jar
new file mode 100644
index 0000000..32875d7
Binary files /dev/null and b/corejava第10版/v1ch13/ResourceTest.jar differ
diff --git a/corejava第10版/v1ch13/applet/NotHelloWorld.java b/corejava第10版/v1ch13/applet/NotHelloWorld.java
new file mode 100644
index 0000000..8bcccf0
--- /dev/null
+++ b/corejava第10版/v1ch13/applet/NotHelloWorld.java
@@ -0,0 +1,20 @@
+package applet;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.24 2015-06-12
+ * @author Cay Horstmann
+ */
+public class NotHelloWorld extends JApplet
+{
+ public void init()
+ {
+ EventQueue.invokeLater(() -> {
+ JLabel label = new JLabel("Not a Hello, World applet",
+ SwingConstants.CENTER);
+ add(label);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch13/chart/Chart.html b/corejava第10版/v1ch13/chart/Chart.html
new file mode 100644
index 0000000..656662d
--- /dev/null
+++ b/corejava第10版/v1ch13/chart/Chart.html
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/corejava第10版/v1ch13/chart/Chart.java b/corejava第10版/v1ch13/chart/Chart.java
new file mode 100644
index 0000000..732cb4b
--- /dev/null
+++ b/corejava第10版/v1ch13/chart/Chart.java
@@ -0,0 +1,129 @@
+package chart;
+
+import java.awt.*;
+import java.awt.font.*;
+import java.awt.geom.*;
+import javax.swing.*;
+
+/**
+ * @version 1.34 2015-06-12
+ * @author Cay Horstmann
+ */
+public class Chart extends JApplet
+{
+ public void init()
+ {
+ EventQueue.invokeLater(() -> {
+ String v = getParameter("values");
+ if (v == null) return;
+ int n = Integer.parseInt(v);
+ double[] values = new double[n];
+ String[] names = new String[n];
+ for (int i = 0; i < n; i++)
+ {
+ values[i] = Double.parseDouble(getParameter("value." + (i + 1)));
+ names[i] = getParameter("name." + (i + 1));
+ }
+
+ add(new ChartComponent(values, names, getParameter("title")));
+ });
+ }
+}
+
+/**
+ * A component that draws a bar chart.
+ */
+class ChartComponent extends JComponent
+{
+ private double[] values;
+ private String[] names;
+ private String title;
+
+ /**
+ * Constructs a ChartComponent.
+ * @param v the array of values for the chart
+ * @param n the array of names for the values
+ * @param t the title of the chart
+ */
+ public ChartComponent(double[] v, String[] n, String t)
+ {
+ values = v;
+ names = n;
+ title = t;
+ }
+
+ public void paintComponent(Graphics g)
+ {
+ Graphics2D g2 = (Graphics2D) g;
+
+ // compute the minimum and maximum values
+ if (values == null) return;
+ double minValue = 0;
+ double maxValue = 0;
+ for (double v : values)
+ {
+ if (minValue > v) minValue = v;
+ if (maxValue < v) maxValue = v;
+ }
+ if (maxValue == minValue) return;
+
+ int panelWidth = getWidth();
+ int panelHeight = getHeight();
+
+ Font titleFont = new Font("SansSerif", Font.BOLD, 20);
+ Font labelFont = new Font("SansSerif", Font.PLAIN, 10);
+
+ // compute the extent of the title
+ FontRenderContext context = g2.getFontRenderContext();
+ Rectangle2D titleBounds = titleFont.getStringBounds(title, context);
+ double titleWidth = titleBounds.getWidth();
+ double top = titleBounds.getHeight();
+
+ // draw the title
+ double y = -titleBounds.getY(); // ascent
+ double x = (panelWidth - titleWidth) / 2;
+ g2.setFont(titleFont);
+ g2.drawString(title, (float) x, (float) y);
+
+ // compute the extent of the bar labels
+ LineMetrics labelMetrics = labelFont.getLineMetrics("", context);
+ double bottom = labelMetrics.getHeight();
+
+ y = panelHeight - labelMetrics.getDescent();
+ g2.setFont(labelFont);
+
+ // get the scale factor and width for the bars
+ double scale = (panelHeight - top - bottom) / (maxValue - minValue);
+ int barWidth = panelWidth / values.length;
+
+ // draw the bars
+ for (int i = 0; i < values.length; i++)
+ {
+ // get the coordinates of the bar rectangle
+ double x1 = i * barWidth + 1;
+ double y1 = top;
+ double height = values[i] * scale;
+ if (values[i] >= 0)
+ y1 += (maxValue - values[i]) * scale;
+ else
+ {
+ y1 += maxValue * scale;
+ height = -height;
+ }
+
+ // fill the bar and draw the bar outline
+ Rectangle2D rect = new Rectangle2D.Double(x1, y1, barWidth - 2, height);
+ g2.setPaint(Color.RED);
+ g2.fill(rect);
+ g2.setPaint(Color.BLACK);
+ g2.draw(rect);
+
+ // draw the centered label below the bar
+ Rectangle2D labelBounds = labelFont.getStringBounds(names[i], context);
+
+ double labelWidth = labelBounds.getWidth();
+ x = x1 + (barWidth - labelWidth) / 2;
+ g2.drawString(names[i], (float) x, (float) y);
+ }
+ }
+}
diff --git a/corejava第10版/v1ch13/java.policy.applet b/corejava第10版/v1ch13/java.policy.applet
new file mode 100644
index 0000000..ba9f51d
--- /dev/null
+++ b/corejava第10版/v1ch13/java.policy.applet
@@ -0,0 +1,7 @@
+/* AUTOMATICALLY GENERATED ON Tue Apr 16 17:20:59 EDT 2002*/
+/* DO NOT EDIT */
+
+grant {
+ permission java.security.AllPermission;
+};
+
diff --git a/corejava第10版/v1ch13/preferences/PreferencesTest.java b/corejava第10版/v1ch13/preferences/PreferencesTest.java
new file mode 100644
index 0000000..2cb08af
--- /dev/null
+++ b/corejava第10版/v1ch13/preferences/PreferencesTest.java
@@ -0,0 +1,127 @@
+package preferences;
+
+import java.awt.*;
+import java.io.*;
+import java.util.prefs.*;
+
+import javax.swing.*;
+import javax.swing.filechooser.*;
+
+/**
+ * A program to test preference settings. The program remembers the frame
+ * position, size, and title.
+ * @version 1.03 2015-06-12
+ * @author Cay Horstmann
+ */
+public class PreferencesTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ PreferencesFrame frame = new PreferencesFrame();
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * A frame that restores position and size from user preferences and updates the
+ * preferences upon exit.
+ */
+class PreferencesFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 200;
+ private Preferences root = Preferences.userRoot();
+ private Preferences node = root.node("/com/horstmann/corejava");
+
+ public PreferencesFrame()
+ {
+ // get position, size, title from preferences
+
+ int left = node.getInt("left", 0);
+ int top = node.getInt("top", 0);
+ int width = node.getInt("width", DEFAULT_WIDTH);
+ int height = node.getInt("height", DEFAULT_HEIGHT);
+ setBounds(left, top, width, height);
+
+ // if no title given, ask user
+
+ String title = node.get("title", "");
+ if (title.equals(""))
+ title = JOptionPane.showInputDialog("Please supply a frame title:");
+ if (title == null) title = "";
+ setTitle(title);
+
+ // set up file chooser that shows XML files
+
+ final JFileChooser chooser = new JFileChooser();
+ chooser.setCurrentDirectory(new File("."));
+ chooser.setFileFilter(new FileNameExtensionFilter("XML files", "xml"));
+
+ // set up menus
+
+ JMenuBar menuBar = new JMenuBar();
+ setJMenuBar(menuBar);
+ JMenu menu = new JMenu("File");
+ menuBar.add(menu);
+
+ JMenuItem exportItem = new JMenuItem("Export preferences");
+ menu.add(exportItem);
+ exportItem
+ .addActionListener(event -> {
+ if (chooser.showSaveDialog(PreferencesFrame.this) == JFileChooser.APPROVE_OPTION)
+ {
+ try
+ {
+ savePreferences();
+ OutputStream out = new FileOutputStream(chooser
+ .getSelectedFile());
+ node.exportSubtree(out);
+ out.close();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ });
+
+ JMenuItem importItem = new JMenuItem("Import preferences");
+ menu.add(importItem);
+ importItem
+ .addActionListener(event -> {
+ if (chooser.showOpenDialog(PreferencesFrame.this) == JFileChooser.APPROVE_OPTION)
+ {
+ try
+ {
+ InputStream in = new FileInputStream(chooser
+ .getSelectedFile());
+ Preferences.importPreferences(in);
+ in.close();
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ });
+
+ JMenuItem exitItem = new JMenuItem("Exit");
+ menu.add(exitItem);
+ exitItem.addActionListener(event -> {
+ savePreferences();
+ System.exit(0);
+ });
+ }
+
+ public void savePreferences()
+ {
+ node.putInt("left", getX());
+ node.putInt("top", getY());
+ node.putInt("width", getWidth());
+ node.putInt("height", getHeight());
+ node.put("title", getTitle());
+ }
+}
diff --git a/corejava第10版/v1ch13/properties/PropertiesTest.java b/corejava第10版/v1ch13/properties/PropertiesTest.java
new file mode 100644
index 0000000..2ae6d07
--- /dev/null
+++ b/corejava第10版/v1ch13/properties/PropertiesTest.java
@@ -0,0 +1,102 @@
+package properties;
+
+import java.awt.EventQueue;
+import java.awt.event.*;
+import java.io.*;
+import java.util.Properties;
+
+import javax.swing.*;
+
+/**
+ * A program to test properties. The program remembers the frame position, size,
+ * and title.
+ * @version 1.01 2015-06-16
+ * @author Cay Horstmann
+ */
+public class PropertiesTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ PropertiesFrame frame = new PropertiesFrame();
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * A frame that restores position and size from a properties file and updates
+ * the properties upon exit.
+ */
+class PropertiesFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 200;
+
+ private File propertiesFile;
+ private Properties settings;
+
+ public PropertiesFrame()
+ {
+ // get position, size, title from properties
+
+ String userDir = System.getProperty("user.home");
+ File propertiesDir = new File(userDir, ".corejava");
+ if (!propertiesDir.exists()) propertiesDir.mkdir();
+ propertiesFile = new File(propertiesDir, "program.properties");
+
+ Properties defaultSettings = new Properties();
+ defaultSettings.setProperty("left", "0");
+ defaultSettings.setProperty("top", "0");
+ defaultSettings.setProperty("width", "" + DEFAULT_WIDTH);
+ defaultSettings.setProperty("height", "" + DEFAULT_HEIGHT);
+ defaultSettings.setProperty("title", "");
+
+ settings = new Properties(defaultSettings);
+
+ if (propertiesFile.exists())
+ try (InputStream in = new FileInputStream(propertiesFile))
+ {
+ settings.load(in);
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+
+ int left = Integer.parseInt(settings.getProperty("left"));
+ int top = Integer.parseInt(settings.getProperty("top"));
+ int width = Integer.parseInt(settings.getProperty("width"));
+ int height = Integer.parseInt(settings.getProperty("height"));
+ setBounds(left, top, width, height);
+
+ // if no title given, ask user
+
+ String title = settings.getProperty("title");
+ if (title.equals(""))
+ title = JOptionPane.showInputDialog("Please supply a frame title:");
+ if (title == null) title = "";
+ setTitle(title);
+
+ addWindowListener(new WindowAdapter()
+ {
+ public void windowClosing(WindowEvent event)
+ {
+ settings.setProperty("left", "" + getX());
+ settings.setProperty("top", "" + getY());
+ settings.setProperty("width", "" + getWidth());
+ settings.setProperty("height", "" + getHeight());
+ settings.setProperty("title", getTitle());
+ try (OutputStream out = new FileOutputStream(propertiesFile))
+ {
+ settings.store(out, "Program Properties");
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ System.exit(0);
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch13/resource/ResourceTest.java b/corejava第10版/v1ch13/resource/ResourceTest.java
new file mode 100644
index 0000000..766a1d8
--- /dev/null
+++ b/corejava第10版/v1ch13/resource/ResourceTest.java
@@ -0,0 +1,50 @@
+package resource;
+
+import java.awt.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import javax.swing.*;
+
+/**
+ * @version 1.41 2015-06-12
+ * @author Cay Horstmann
+ */
+public class ResourceTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new ResourceTestFrame();
+ frame.setTitle("ResourceTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * A frame that loads image and text resources.
+ */
+class ResourceTestFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 300;
+
+ public ResourceTestFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+ URL aboutURL = getClass().getResource("about.gif");
+ Image img = new ImageIcon(aboutURL).getImage();
+ setIconImage(img);
+
+ JTextArea textArea = new JTextArea();
+ InputStream stream = getClass().getResourceAsStream("about.txt");
+ try (Scanner in = new Scanner(stream, "UTF-8"))
+ {
+ while (in.hasNext())
+ textArea.append(in.nextLine() + "\n");
+ }
+ add(textArea);
+ }
+}
diff --git a/corejava第10版/v1ch13/resource/ResourceTest.mf b/corejava第10版/v1ch13/resource/ResourceTest.mf
new file mode 100644
index 0000000..833e890
--- /dev/null
+++ b/corejava第10版/v1ch13/resource/ResourceTest.mf
@@ -0,0 +1 @@
+Main-Class: resource.ResourceTest
diff --git a/corejava第10版/v1ch13/resource/about.gif b/corejava第10版/v1ch13/resource/about.gif
new file mode 100644
index 0000000..ec1c176
Binary files /dev/null and b/corejava第10版/v1ch13/resource/about.gif differ
diff --git a/corejava第10版/v1ch13/resource/about.txt b/corejava第10版/v1ch13/resource/about.txt
new file mode 100644
index 0000000..ba313a4
--- /dev/null
+++ b/corejava第10版/v1ch13/resource/about.txt
@@ -0,0 +1,5 @@
+Core Java: Fundamentals
+10th Edition
+Cay Horstmann and Gary Cornell
+Copyright © 2016
+Prentice-Hall
diff --git a/corejava第10版/v1ch13/serviceLoader/Cipher.java b/corejava第10版/v1ch13/serviceLoader/Cipher.java
new file mode 100644
index 0000000..d5a7994
--- /dev/null
+++ b/corejava第10版/v1ch13/serviceLoader/Cipher.java
@@ -0,0 +1,8 @@
+package serviceLoader;
+
+public interface Cipher
+{
+ byte[] encrypt(byte[] source, byte[] key);
+ byte[] decrypt(byte[] source, byte[] key);
+ int strength();
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch13/serviceLoader/ServiceLoaderTest.java b/corejava第10版/v1ch13/serviceLoader/ServiceLoaderTest.java
new file mode 100644
index 0000000..243cc45
--- /dev/null
+++ b/corejava第10版/v1ch13/serviceLoader/ServiceLoaderTest.java
@@ -0,0 +1,32 @@
+package serviceLoader;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ServiceLoader;
+
+/**
+ * @version 1.00 2015-06-14
+ * @author Cay Horstmann
+ */
+
+public class ServiceLoaderTest
+{
+ public static ServiceLoader cipherLoader = ServiceLoader
+ .load(Cipher.class);
+
+ public static void main(String[] args) throws UnsupportedEncodingException
+ {
+ Cipher ciph = getCipher(1);
+ String message = "Meet me at the toga party.";
+ byte[] bytes = ciph.encrypt(message.getBytes(), new byte[] { 3 });
+ String encrypted = new String(bytes, "UTF-8");
+ System.out.println(encrypted);
+ }
+
+ public static Cipher getCipher(int minStrength)
+ {
+ for (Cipher cipher : cipherLoader)
+ // .rm Implicitly calls iterator
+ if (cipher.strength() >= minStrength) return cipher;
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch13/serviceLoader/impl/CaesarCipher.java b/corejava第10版/v1ch13/serviceLoader/impl/CaesarCipher.java
new file mode 100644
index 0000000..2386bec
--- /dev/null
+++ b/corejava第10版/v1ch13/serviceLoader/impl/CaesarCipher.java
@@ -0,0 +1,24 @@
+package serviceLoader.impl;
+
+import serviceLoader.Cipher;
+
+public class CaesarCipher implements Cipher
+{
+ public byte[] encrypt(byte[] source, byte[] key)
+ {
+ byte[] result = new byte[source.length];
+ for (int i = 0; i < source.length; i++)
+ result[i] = (byte) (source[i] + key[0]);
+ return result;
+ }
+
+ public byte[] decrypt(byte[] source, byte[] key)
+ {
+ return encrypt(source, new byte[] { (byte) -key[0] });
+ }
+
+ public int strength()
+ {
+ return 1;
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch13/systemInfo/SystemInfo.java b/corejava第10版/v1ch13/systemInfo/SystemInfo.java
new file mode 100644
index 0000000..6a2a446
--- /dev/null
+++ b/corejava第10版/v1ch13/systemInfo/SystemInfo.java
@@ -0,0 +1,25 @@
+package systemInfo;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * This program prints out all system properties.
+ * @version 1.10 2002-07-06
+ * @author Cay Horstmann
+ */
+public class SystemInfo
+{
+ public static void main(String args[])
+ {
+ try
+ {
+ Properties sysprops = System.getProperties();
+ sysprops.store(System.out, "System Properties");
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/corejava第10版/v1ch13/webstart/Calculator.jar b/corejava第10版/v1ch13/webstart/Calculator.jar
new file mode 100644
index 0000000..b8e4e65
Binary files /dev/null and b/corejava第10版/v1ch13/webstart/Calculator.jar differ
diff --git a/corejava第10版/v1ch13/webstart/Calculator.java b/corejava第10版/v1ch13/webstart/Calculator.java
new file mode 100644
index 0000000..1be4a70
--- /dev/null
+++ b/corejava第10版/v1ch13/webstart/Calculator.java
@@ -0,0 +1,21 @@
+package webstart;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * A calculator with a calculation history that can be deployed as a Java Web Start application.
+ * @version 1.04 2015-06-12
+ * @author Cay Horstmann
+ */
+public class Calculator
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ CalculatorFrame frame = new CalculatorFrame();
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch13/webstart/Calculator.jnlp b/corejava第10版/v1ch13/webstart/Calculator.jnlp
new file mode 100644
index 0000000..1bb3ccb
--- /dev/null
+++ b/corejava第10版/v1ch13/webstart/Calculator.jnlp
@@ -0,0 +1,20 @@
+
+
+
+ Calculator Demo Application
+ Cay S. Horstmann
+ Web Start Calculator
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/corejava第10版/v1ch13/webstart/CalculatorFrame.java b/corejava第10版/v1ch13/webstart/CalculatorFrame.java
new file mode 100644
index 0000000..912b528
--- /dev/null
+++ b/corejava第10版/v1ch13/webstart/CalculatorFrame.java
@@ -0,0 +1,155 @@
+package webstart;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.jnlp.BasicService;
+import javax.jnlp.FileContents;
+import javax.jnlp.FileOpenService;
+import javax.jnlp.FileSaveService;
+import javax.jnlp.PersistenceService;
+import javax.jnlp.ServiceManager;
+import javax.jnlp.UnavailableServiceException;
+import javax.swing.JFrame;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+
+/**
+ * A frame with a calculator panel and a menu to load and save the calculator history.
+ */
+public class CalculatorFrame extends JFrame
+{
+ private CalculatorPanel panel;
+
+ public CalculatorFrame()
+ {
+ setTitle();
+ panel = new CalculatorPanel();
+ add(panel);
+
+ JMenu fileMenu = new JMenu("File");
+ JMenuBar menuBar = new JMenuBar();
+ menuBar.add(fileMenu);
+ setJMenuBar(menuBar);
+
+ JMenuItem openItem = fileMenu.add("Open");
+ openItem.addActionListener(event -> open());
+ JMenuItem saveItem = fileMenu.add("Save");
+ saveItem.addActionListener(event -> save());
+
+ pack();
+ }
+
+ /**
+ * Gets the title from the persistent store or asks the user for the title if there is no prior
+ * entry.
+ */
+ public void setTitle()
+ {
+ try
+ {
+ String title = null;
+
+ BasicService basic = (BasicService) ServiceManager.lookup("javax.jnlp.BasicService");
+ URL codeBase = basic.getCodeBase();
+
+ PersistenceService service = (PersistenceService) ServiceManager
+ .lookup("javax.jnlp.PersistenceService");
+ URL key = new URL(codeBase, "title");
+
+ try
+ {
+ FileContents contents = service.get(key);
+ InputStream in = contents.getInputStream();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+ title = reader.readLine();
+ }
+ catch (FileNotFoundException e)
+ {
+ title = JOptionPane.showInputDialog("Please supply a frame title:");
+ if (title == null) return;
+
+ service.create(key, 100);
+ FileContents contents = service.get(key);
+ OutputStream out = contents.getOutputStream(true);
+ PrintStream printOut = new PrintStream(out);
+ printOut.print(title);
+ }
+ setTitle(title);
+ }
+ catch (UnavailableServiceException | IOException e)
+ {
+ JOptionPane.showMessageDialog(this, e);
+ }
+ }
+
+ /**
+ * Opens a history file and updates the display.
+ */
+ public void open()
+ {
+ try
+ {
+ FileOpenService service = (FileOpenService) ServiceManager
+ .lookup("javax.jnlp.FileOpenService");
+ FileContents contents = service.openFileDialog(".", new String[] { "txt" });
+
+ JOptionPane.showMessageDialog(this, contents.getName());
+ if (contents != null)
+ {
+ InputStream in = contents.getInputStream();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+ String line;
+ while ((line = reader.readLine()) != null)
+ {
+ panel.append(line);
+ panel.append("\n");
+ }
+ }
+ }
+ catch (UnavailableServiceException e)
+ {
+ JOptionPane.showMessageDialog(this, e);
+ }
+ catch (IOException e)
+ {
+ JOptionPane.showMessageDialog(this, e);
+ }
+ }
+
+ /**
+ * Saves the calculator history to a file.
+ */
+ public void save()
+ {
+ try
+ {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ PrintStream printOut = new PrintStream(out);
+ printOut.print(panel.getText());
+ InputStream data = new ByteArrayInputStream(out.toByteArray());
+ FileSaveService service = (FileSaveService) ServiceManager
+ .lookup("javax.jnlp.FileSaveService");
+ service.saveFileDialog(".", new String[] { "txt" }, data, "calc.txt");
+ }
+ catch (UnavailableServiceException e)
+ {
+ JOptionPane.showMessageDialog(this, e);
+ }
+ catch (IOException e)
+ {
+ JOptionPane.showMessageDialog(this, e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch13/webstart/CalculatorPanel.java b/corejava第10版/v1ch13/webstart/CalculatorPanel.java
new file mode 100644
index 0000000..b9e462f
--- /dev/null
+++ b/corejava第10版/v1ch13/webstart/CalculatorPanel.java
@@ -0,0 +1,168 @@
+package webstart;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.text.*;
+
+/**
+ A panel with calculator buttons and a result display.
+*/
+public class CalculatorPanel extends JPanel
+{
+ private JTextArea display;
+ private JPanel panel;
+ private double result;
+ private String lastCommand;
+ private boolean start;
+
+ /**
+ Lays out the panel.
+ */
+ public CalculatorPanel()
+ {
+ setLayout(new BorderLayout());
+
+ result = 0;
+ lastCommand = "=";
+ start = true;
+
+ // add the display
+
+ display = new JTextArea(10, 20);
+
+ add(new JScrollPane(display), BorderLayout.NORTH);
+
+ ActionListener insert = new InsertAction();
+ ActionListener command = new CommandAction();
+
+ // add the buttons in a 4 x 4 grid
+
+ panel = new JPanel();
+ panel.setLayout(new GridLayout(4, 4));
+
+ addButton("7", insert);
+ addButton("8", insert);
+ addButton("9", insert);
+ addButton("/", command);
+
+ addButton("4", insert);
+ addButton("5", insert);
+ addButton("6", insert);
+ addButton("*", command);
+
+ addButton("1", insert);
+ addButton("2", insert);
+ addButton("3", insert);
+ addButton("-", command);
+
+ addButton("0", insert);
+ addButton(".", insert);
+ addButton("=", command);
+ addButton("+", command);
+
+ add(panel, BorderLayout.CENTER);
+ }
+
+ /**
+ Gets the history text.
+ @return the calculator history
+ */
+ public String getText()
+ {
+ return display.getText();
+ }
+
+ /**
+ Appends a string to the history text.
+ @param s the string to append
+ */
+ public void append(String s)
+ {
+ display.append(s);
+ }
+
+ /**
+ Adds a button to the center panel.
+ @param label the button label
+ @param listener the button listener
+ */
+ private void addButton(String label, ActionListener listener)
+ {
+ JButton button = new JButton(label);
+ button.addActionListener(listener);
+ panel.add(button);
+ }
+
+ /**
+ This action inserts the button action string to the
+ end of the display text.
+ */
+ private class InsertAction implements ActionListener
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ String input = event.getActionCommand();
+ start = false;
+ display.append(input);
+ }
+ }
+
+ /**
+ This action executes the command that the button
+ action string denotes.
+ */
+ private class CommandAction implements ActionListener
+ {
+ public void actionPerformed(ActionEvent event)
+ {
+ String command = event.getActionCommand();
+
+ if (start)
+ {
+ if (command.equals("-"))
+ {
+ display.append(command);
+ start = false;
+ }
+ else
+ lastCommand = command;
+ }
+ else
+ {
+ try
+ {
+ int lines = display.getLineCount();
+ int lineStart = display.getLineStartOffset(lines - 1);
+ int lineEnd = display.getLineEndOffset(lines - 1);
+ String value = display.getText(lineStart, lineEnd - lineStart);
+ display.append(" ");
+ display.append(command);
+ calculate(Double.parseDouble(value));
+ if (command.equals("="))
+ display.append("\n" + result);
+ lastCommand = command;
+ display.append("\n");
+ start = true;
+ }
+ catch (BadLocationException e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ Carries out the pending calculation.
+ @param x the value to be accumulated with the prior result.
+ */
+ public void calculate(double x)
+ {
+ if (lastCommand.equals("+")) result += x;
+ else if (lastCommand.equals("-")) result -= x;
+ else if (lastCommand.equals("*")) result *= x;
+ else if (lastCommand.equals("/")) result /= x;
+ else if (lastCommand.equals("=")) result = x;
+ }
+}
diff --git a/corejava第10版/v1ch13/webstart/calc_icon32.png b/corejava第10版/v1ch13/webstart/calc_icon32.png
new file mode 100644
index 0000000..b4cdb48
Binary files /dev/null and b/corejava第10版/v1ch13/webstart/calc_icon32.png differ
diff --git a/corejava第10版/v1ch13/webstart/calc_icon64.png b/corejava第10版/v1ch13/webstart/calc_icon64.png
new file mode 100644
index 0000000..fd6e439
Binary files /dev/null and b/corejava第10版/v1ch13/webstart/calc_icon64.png differ
diff --git a/corejava第10版/v1ch14/blockingQueue/BlockingQueueTest.java b/corejava第10版/v1ch14/blockingQueue/BlockingQueueTest.java
new file mode 100644
index 0000000..7ea691c
--- /dev/null
+++ b/corejava第10版/v1ch14/blockingQueue/BlockingQueueTest.java
@@ -0,0 +1,101 @@
+package blockingQueue;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+/**
+ * @version 1.02 2015-06-21
+ * @author Cay Horstmann
+ */
+public class BlockingQueueTest
+{
+ private static final int FILE_QUEUE_SIZE = 10;
+ private static final int SEARCH_THREADS = 100;
+ private static final File DUMMY = new File("");
+ private static BlockingQueue queue = new ArrayBlockingQueue<>(FILE_QUEUE_SIZE);
+
+ public static void main(String[] args)
+ {
+ try (Scanner in = new Scanner(System.in))
+ {
+ System.out.print("Enter base directory (e.g. /opt/jdk1.8.0/src): ");
+ String directory = in.nextLine();
+ System.out.print("Enter keyword (e.g. volatile): ");
+ String keyword = in.nextLine();
+
+ Runnable enumerator = () -> {
+ try
+ {
+ enumerate(new File(directory));
+ queue.put(DUMMY);
+ }
+ catch (InterruptedException e)
+ {
+ }
+ };
+
+ new Thread(enumerator).start();
+ for (int i = 1; i <= SEARCH_THREADS; i++) {
+ Runnable searcher = () -> {
+ try
+ {
+ boolean done = false;
+ while (!done)
+ {
+ File file = queue.take();
+ if (file == DUMMY)
+ {
+ queue.put(file);
+ done = true;
+ }
+ else search(file, keyword);
+ }
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ catch (InterruptedException e)
+ {
+ }
+ };
+ new Thread(searcher).start();
+ }
+ }
+ }
+
+ /**
+ * Recursively enumerates all files in a given directory and its subdirectories.
+ * @param directory the directory in which to start
+ */
+ public static void enumerate(File directory) throws InterruptedException
+ {
+ File[] files = directory.listFiles();
+ for (File file : files)
+ {
+ if (file.isDirectory()) enumerate(file);
+ else queue.put(file);
+ }
+ }
+
+ /**
+ * Searches a file for a given keyword and prints all matching lines.
+ * @param file the file to search
+ * @param keyword the keyword to search for
+ */
+ public static void search(File file, String keyword) throws IOException
+ {
+ try (Scanner in = new Scanner(file, "UTF-8"))
+ {
+ 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);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch14/bounce/Ball.java b/corejava第10版/v1ch14/bounce/Ball.java
new file mode 100644
index 0000000..1a7c987
--- /dev/null
+++ b/corejava第10版/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
+{
+ 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;
+
+ /**
+ * 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);
+ }
+}
diff --git a/corejava第10版/v1ch14/bounce/BallComponent.java b/corejava第10版/v1ch14/bounce/BallComponent.java
new file mode 100644
index 0000000..0ebf36e
--- /dev/null
+++ b/corejava第10版/v1ch14/bounce/BallComponent.java
@@ -0,0 +1,39 @@
+package bounce;
+
+import java.awt.*;
+import java.util.*;
+import javax.swing.*;
+
+/**
+ * The component that draws the balls.
+ * @version 1.34 2012-01-26
+ * @author Cay Horstmann
+ */
+public class BallComponent extends JPanel
+{
+ private static final int DEFAULT_WIDTH = 450;
+ private static final int DEFAULT_HEIGHT = 350;
+
+ private java.util.List balls = new ArrayList<>();
+
+ /**
+ * 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());
+ }
+ }
+
+ public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); }
+}
diff --git a/corejava第10版/v1ch14/bounce/Bounce.java b/corejava第10版/v1ch14/bounce/Bounce.java
new file mode 100644
index 0000000..80393d2
--- /dev/null
+++ b/corejava第10版/v1ch14/bounce/Bounce.java
@@ -0,0 +1,83 @@
+package bounce;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+/**
+ * Shows an animated bouncing ball.
+ * @version 1.34 2015-06-21
+ * @author Cay Horstmann
+ */
+public class Bounce
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new BounceFrame();
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * The frame with ball component and buttons.
+ */
+class BounceFrame extends JFrame
+{
+ private BallComponent comp;
+ public static final int STEPS = 1000;
+ public static final int DELAY = 3;
+
+ /**
+ * Constructs the frame with the component for showing the bouncing ball and
+ * Start and Close buttons
+ */
+ public BounceFrame()
+ {
+ setTitle("Bounce");
+ comp = new BallComponent();
+ add(comp, BorderLayout.CENTER);
+ JPanel buttonPanel = new JPanel();
+ addButton(buttonPanel, "Start", event -> addBall());
+ addButton(buttonPanel, "Close", event -> System.exit(0));
+ add(buttonPanel, BorderLayout.SOUTH);
+ pack();
+ }
+
+ /**
+ * 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)
+ {
+ }
+ }
+}
diff --git a/corejava第10版/v1ch14/bounceThread/Ball.java b/corejava第10版/v1ch14/bounceThread/Ball.java
new file mode 100644
index 0000000..d1545fc
--- /dev/null
+++ b/corejava第10版/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
+{
+ 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;
+
+ /**
+ 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);
+ }
+}
diff --git a/corejava第10版/v1ch14/bounceThread/BallComponent.java b/corejava第10版/v1ch14/bounceThread/BallComponent.java
new file mode 100644
index 0000000..6643b1a
--- /dev/null
+++ b/corejava第10版/v1ch14/bounceThread/BallComponent.java
@@ -0,0 +1,38 @@
+package bounceThread;
+
+import java.awt.*;
+import java.util.*;
+import javax.swing.*;
+
+/**
+ * The component that draws the balls.
+ * @version 1.34 2012-01-26
+ * @author Cay Horstmann
+ */
+public class BallComponent extends JComponent
+{
+ private static final int DEFAULT_WIDTH = 450;
+ private static final int DEFAULT_HEIGHT = 350;
+
+ private java.util.List balls = new ArrayList<>();
+
+ /**
+ * 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());
+ }
+ }
+
+ public Dimension getPreferredSize() { return new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); }
+}
diff --git a/corejava第10版/v1ch14/bounceThread/BounceThread.java b/corejava第10版/v1ch14/bounceThread/BounceThread.java
new file mode 100644
index 0000000..b137c85
--- /dev/null
+++ b/corejava第10版/v1ch14/bounceThread/BounceThread.java
@@ -0,0 +1,88 @@
+package bounceThread;
+
+import java.awt.*;
+import java.awt.event.*;
+
+import javax.swing.*;
+
+/**
+ * Shows animated bouncing balls.
+ * @version 1.34 2015-06-21
+ * @author Cay Horstmann
+ */
+public class BounceThread
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new BounceFrame();
+ frame.setTitle("BounceThread");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * The frame with panel and buttons.
+ */
+class BounceFrame extends JFrame
+{
+ private BallComponent comp;
+ public static final int STEPS = 1000;
+ public static final int DELAY = 5;
+
+
+ /**
+ * Constructs the frame with the component for showing the bouncing ball and
+ * Start and Close buttons
+ */
+ public BounceFrame()
+ {
+ comp = new BallComponent();
+ add(comp, BorderLayout.CENTER);
+ JPanel buttonPanel = new JPanel();
+ addButton(buttonPanel, "Start", event -> addBall());
+ addButton(buttonPanel, "Close", event -> System.exit(0));
+ add(buttonPanel, BorderLayout.SOUTH);
+ pack();
+ }
+
+ /**
+ * 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 ball = new Ball();
+ comp.add(ball);
+ Runnable r = () -> {
+ try
+ {
+ for (int i = 1; i <= STEPS; i++)
+ {
+ ball.move(comp.getBounds());
+ comp.repaint();
+ Thread.sleep(DELAY);
+ }
+ }
+ catch (InterruptedException e)
+ {
+ }
+ };
+ Thread t = new Thread(r);
+ t.start();
+ }
+}
diff --git a/corejava第10版/v1ch14/forkJoin/ForkJoinTest.java b/corejava第10版/v1ch14/forkJoin/ForkJoinTest.java
new file mode 100644
index 0000000..67161b5
--- /dev/null
+++ b/corejava第10版/v1ch14/forkJoin/ForkJoinTest.java
@@ -0,0 +1,61 @@
+package forkJoin;
+
+import java.util.concurrent.*;
+import java.util.function.*;
+
+/**
+ * This program demonstrates the fork-join framework.
+ * @version 1.01 2015-06-21
+ * @author Cay Horstmann
+ */
+public class ForkJoinTest
+{
+ public static void main(String[] args)
+ {
+ final int SIZE = 10000000;
+ double[] numbers = new double[SIZE];
+ for (int i = 0; i < SIZE; i++) numbers[i] = Math.random();
+ Counter counter = new Counter(numbers, 0, numbers.length, x -> x > 0.5);
+ ForkJoinPool pool = new ForkJoinPool();
+ pool.invoke(counter);
+ System.out.println(counter.join());
+ }
+}
+
+class Counter extends RecursiveTask
+{
+ public static final int THRESHOLD = 1000;
+ private double[] values;
+ private int from;
+ private int to;
+ private DoublePredicate filter;
+
+ public Counter(double[] values, int from, int to, DoublePredicate filter)
+ {
+ this.values = values;
+ this.from = from;
+ this.to = to;
+ this.filter = filter;
+ }
+
+ protected Integer compute()
+ {
+ if (to - from < THRESHOLD)
+ {
+ int count = 0;
+ for (int i = from; i < to; i++)
+ {
+ if (filter.test(values[i])) count++;
+ }
+ return count;
+ }
+ else
+ {
+ int mid = (from + to) / 2;
+ Counter first = new Counter(values, from, mid, filter);
+ Counter second = new Counter(values, mid, to, filter);
+ invokeAll(first, second);
+ return first.join() + second.join();
+ }
+ }
+}
diff --git a/corejava第10版/v1ch14/future/FutureTest.java b/corejava第10版/v1ch14/future/FutureTest.java
new file mode 100644
index 0000000..5e758f9
--- /dev/null
+++ b/corejava第10版/v1ch14/future/FutureTest.java
@@ -0,0 +1,123 @@
+package future;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+/**
+ * @version 1.01 2012-01-26
+ * @author Cay Horstmann
+ */
+public class FutureTest
+{
+ public static void main(String[] args)
+ {
+ try (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
+{
+ private File directory;
+ private String keyword;
+
+ /**
+ * 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()
+ {
+ int count = 0;
+ try
+ {
+ File[] files = directory.listFiles();
+ List> 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
+ {
+ try (Scanner in = new Scanner(file, "UTF-8"))
+ {
+ boolean found = false;
+ while (!found && in.hasNextLine())
+ {
+ String line = in.nextLine();
+ if (line.contains(keyword)) found = true;
+ }
+ return found;
+ }
+ }
+ catch (IOException e)
+ {
+ return false;
+ }
+ }
+}
diff --git a/corejava第10版/v1ch14/swing/SwingThreadTest.java b/corejava第10版/v1ch14/swing/SwingThreadTest.java
new file mode 100644
index 0000000..8f56463
--- /dev/null
+++ b/corejava第10版/v1ch14/swing/SwingThreadTest.java
@@ -0,0 +1,132 @@
+package swing;
+
+import java.awt.*;
+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.24 2015-06-21
+ * @author Cay Horstmann
+ */
+public class SwingThreadTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() -> {
+ JFrame frame = new SwingThreadFrame();
+ frame.setTitle("SwingThreadTest");
+ 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()
+ {
+ 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(event ->
+ new Thread(new GoodWorkerRunnable(combo)).start());
+ panel.add(goodButton);
+ JButton badButton = new JButton("Bad");
+ badButton.addActionListener(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
+{
+ private JComboBox combo;
+ private Random generator;
+
+ 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)
+ {
+ }
+ }
+}
+
+/**
+ * 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
+{
+ private JComboBox combo;
+ private Random generator;
+
+ public GoodWorkerRunnable(JComboBox aCombo)
+ {
+ combo = aCombo;
+ generator = new Random();
+ }
+
+ public void run()
+ {
+ try
+ {
+ while (true)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ 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)
+ {
+ }
+ }
+}
diff --git a/corejava第10版/v1ch14/swingWorker/SwingWorkerTest.java b/corejava第10版/v1ch14/swingWorker/SwingWorkerTest.java
new file mode 100644
index 0000000..0b810a9
--- /dev/null
+++ b/corejava第10版/v1ch14/swingWorker/SwingWorkerTest.java
@@ -0,0 +1,161 @@
+package swingWorker;
+
+import java.awt.*;
+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.11 2015-06-21
+ * @author Cay Horstmann
+ */
+public class SwingWorkerTest
+{
+ public static void main(String[] args) throws Exception
+ {
+ EventQueue.invokeLater(() -> {
+ 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
+{
+ private JFileChooser chooser;
+ private JTextArea textArea;
+ private JLabel statusLine;
+ private JMenuItem openItem;
+ private JMenuItem cancelItem;
+ private SwingWorker textReader;
+ public static final int TEXT_ROWS = 20;
+ public static final int TEXT_COLUMNS = 60;
+
+ public SwingWorkerFrame()
+ {
+ chooser = new JFileChooser();
+ chooser.setCurrentDirectory(new File("."));
+
+ textArea = new JTextArea(TEXT_ROWS, TEXT_COLUMNS);
+ add(new JScrollPane(textArea));
+
+ 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(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(event -> textReader.cancel(true));
+ pack();
+ }
+
+ private class ProgressData
+ {
+ public int number;
+ public String line;
+ }
+
+ private class TextReader extends SwingWorker
+ {
+ private File file;
+ private StringBuilder text = new StringBuilder();
+
+ 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;
+ try (Scanner in = new Scanner(new FileInputStream(file), "UTF-8"))
+ {
+ while (in.hasNextLine())
+ {
+ String line = in.nextLine();
+ lineNumber++;
+ text.append(line).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).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);
+ }
+ };
+}
diff --git a/corejava第10版/v1ch14/synch/Bank.java b/corejava第10版/v1ch14/synch/Bank.java
new file mode 100644
index 0000000..3c06fc0
--- /dev/null
+++ b/corejava第10版/v1ch14/synch/Bank.java
@@ -0,0 +1,86 @@
+package synch;
+
+import java.util.*;
+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
+{
+ private final double[] accounts;
+ private Lock bankLock;
+ private Condition sufficientFunds;
+
+ /**
+ * 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];
+ Arrays.fill(accounts, 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;
+ }
+}
diff --git a/corejava第10版/v1ch14/synch/SynchBankTest.java b/corejava第10版/v1ch14/synch/SynchBankTest.java
new file mode 100644
index 0000000..2a07e1a
--- /dev/null
+++ b/corejava第10版/v1ch14/synch/SynchBankTest.java
@@ -0,0 +1,40 @@
+package synch;
+
+/**
+ * This program shows how multiple threads can safely access a data structure.
+ * @version 1.31 2015-06-21
+ * @author Cay Horstmann
+ */
+public class SynchBankTest
+{
+ public static final int NACCOUNTS = 100;
+ public static final double INITIAL_BALANCE = 1000;
+ public static final double MAX_AMOUNT = 1000;
+ public static final int DELAY = 10;
+
+ public static void main(String[] args)
+ {
+ Bank bank = new Bank(NACCOUNTS, INITIAL_BALANCE);
+ for (int i = 0; i < NACCOUNTS; i++)
+ {
+ int fromAccount = i;
+ Runnable r = () -> {
+ try
+ {
+ while (true)
+ {
+ int toAccount = (int) (bank.size() * Math.random());
+ double amount = MAX_AMOUNT * Math.random();
+ bank.transfer(fromAccount, toAccount, amount);
+ Thread.sleep((int) (DELAY * Math.random()));
+ }
+ }
+ catch (InterruptedException e)
+ {
+ }
+ };
+ Thread t = new Thread(r);
+ t.start();
+ }
+ }
+}
diff --git a/corejava第10版/v1ch14/synch2/Bank.java b/corejava第10版/v1ch14/synch2/Bank.java
new file mode 100644
index 0000000..2052cc9
--- /dev/null
+++ b/corejava第10版/v1ch14/synch2/Bank.java
@@ -0,0 +1,65 @@
+package synch2;
+
+import java.util.*;
+
+/**
+ * A bank with a number of bank accounts that uses synchronization primitives.
+ * @version 1.30 2004-08-01
+ * @author Cay Horstmann
+ */
+public class Bank
+{
+ private final double[] accounts;
+
+ /**
+ * 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];
+ Arrays.fill(accounts, 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;
+ }
+}
diff --git a/corejava第10版/v1ch14/synch2/SynchBankTest2.java b/corejava第10版/v1ch14/synch2/SynchBankTest2.java
new file mode 100644
index 0000000..582ecec
--- /dev/null
+++ b/corejava第10版/v1ch14/synch2/SynchBankTest2.java
@@ -0,0 +1,41 @@
+package synch2;
+
+/**
+ * This program shows how multiple threads can safely access a data structure,
+ * using synchronized methods.
+ * @version 1.31 2015-06-21
+ * @author Cay Horstmann
+ */
+public class SynchBankTest2
+{
+ public static final int NACCOUNTS = 100;
+ public static final double INITIAL_BALANCE = 1000;
+ public static final double MAX_AMOUNT = 1000;
+ public static final int DELAY = 10;
+
+ public static void main(String[] args)
+ {
+ Bank bank = new Bank(NACCOUNTS, INITIAL_BALANCE);
+ for (int i = 0; i < NACCOUNTS; i++)
+ {
+ int fromAccount = i;
+ Runnable r = () -> {
+ try
+ {
+ while (true)
+ {
+ int toAccount = (int) (bank.size() * Math.random());
+ double amount = MAX_AMOUNT * Math.random();
+ bank.transfer(fromAccount, toAccount, amount);
+ Thread.sleep((int) (DELAY * Math.random()));
+ }
+ }
+ catch (InterruptedException e)
+ {
+ }
+ };
+ Thread t = new Thread(r);
+ t.start();
+ }
+ }
+}
diff --git a/corejava第10版/v1ch14/threadPool/ThreadPoolTest.java b/corejava第10版/v1ch14/threadPool/ThreadPoolTest.java
new file mode 100644
index 0000000..c7765ec
--- /dev/null
+++ b/corejava第10版/v1ch14/threadPool/ThreadPoolTest.java
@@ -0,0 +1,130 @@
+package threadPool;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+/**
+ * @version 1.02 2015-06-21
+ * @author Cay Horstmann
+ */
+public class ThreadPoolTest
+{
+ public static void main(String[] args) throws Exception
+ {
+ try (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
+{
+ private File directory;
+ private String keyword;
+ private ExecutorService pool;
+ private int count;
+
+ /**
+ * 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();
+ List> 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
+ {
+ try (Scanner in = new Scanner(file, "UTF-8"))
+ {
+ boolean found = false;
+ while (!found && in.hasNextLine())
+ {
+ String line = in.nextLine();
+ if (line.contains(keyword)) found = true;
+ }
+ return found;
+ }
+ }
+ catch (IOException e)
+ {
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v1ch14/unsynch/Bank.java b/corejava第10版/v1ch14/unsynch/Bank.java
new file mode 100644
index 0000000..9f49c6f
--- /dev/null
+++ b/corejava第10版/v1ch14/unsynch/Bank.java
@@ -0,0 +1,63 @@
+package unsynch;
+
+import java.util.*;
+
+/**
+ * A bank with a number of bank accounts.
+ * @version 1.30 2004-08-01
+ * @author Cay Horstmann
+ */
+public class Bank
+{
+ private final double[] accounts;
+
+ /**
+ * 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];
+ Arrays.fill(accounts, 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;
+ }
+}
diff --git a/corejava第10版/v1ch14/unsynch/UnsynchBankTest.java b/corejava第10版/v1ch14/unsynch/UnsynchBankTest.java
new file mode 100644
index 0000000..2da1e47
--- /dev/null
+++ b/corejava第10版/v1ch14/unsynch/UnsynchBankTest.java
@@ -0,0 +1,40 @@
+package unsynch;
+
+/**
+ * This program shows data corruption when multiple threads access a data structure.
+ * @version 1.31 2015-06-21
+ * @author Cay Horstmann
+ */
+public class UnsynchBankTest
+{
+ public static final int NACCOUNTS = 100;
+ public static final double INITIAL_BALANCE = 1000;
+ public static final double MAX_AMOUNT = 1000;
+ public static final int DELAY = 10;
+
+ public static void main(String[] args)
+ {
+ Bank bank = new Bank(NACCOUNTS, INITIAL_BALANCE);
+ for (int i = 0; i < NACCOUNTS; i++)
+ {
+ int fromAccount = i;
+ Runnable r = () -> {
+ try
+ {
+ while (true)
+ {
+ int toAccount = (int) (bank.size() * Math.random());
+ double amount = MAX_AMOUNT * Math.random();
+ bank.transfer(fromAccount, toAccount, amount);
+ Thread.sleep((int) (DELAY * Math.random()));
+ }
+ }
+ catch (InterruptedException e)
+ {
+ }
+ };
+ Thread t = new Thread(r);
+ t.start();
+ }
+ }
+}
diff --git a/javacore第11版/corejava/v2ch01/cities.txt b/corejava第10版/v2ch01/cities.txt
similarity index 100%
rename from javacore第11版/corejava/v2ch01/cities.txt
rename to corejava第10版/v2ch01/cities.txt
diff --git a/corejava第10版/v2ch01/collecting/CollectingIntoMaps.java b/corejava第10版/v2ch01/collecting/CollectingIntoMaps.java
new file mode 100644
index 0000000..a0bacde
--- /dev/null
+++ b/corejava第10版/v2ch01/collecting/CollectingIntoMaps.java
@@ -0,0 +1,83 @@
+package collecting;
+
+import java.io.*;
+import java.util.*;
+import java.util.function.*;
+import java.util.stream.*;
+
+public class CollectingIntoMaps
+{
+
+ public static class Person
+ {
+ private int id;
+ private String name;
+
+ public Person(int id, String name)
+ {
+ this.id = id;
+ this.name = name;
+ }
+
+ public int getId()
+ {
+ return id;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public String toString()
+ {
+ return getClass().getName() + "[id=" + id + ",name=" + name + "]";
+ }
+ }
+
+ public static Stream people()
+ {
+ return Stream.of(new Person(1001, "Peter"), new Person(1002, "Paul"),
+ new Person(1003, "Mary"));
+ }
+
+ public static void main(String[] args) throws IOException
+ {
+ Map idToName = people().collect(
+ Collectors.toMap(Person::getId, Person::getName));
+ System.out.println("idToName: " + idToName);
+
+ Map idToPerson = people().collect(
+ Collectors.toMap(Person::getId, Function.identity()));
+ System.out.println("idToPerson: " + idToPerson.getClass().getName()
+ + idToPerson);
+
+ idToPerson = people().collect(
+ Collectors.toMap(Person::getId, Function.identity(), (
+ existingValue, newValue) -> {
+ throw new IllegalStateException();
+ }, TreeMap::new));
+ System.out.println("idToPerson: " + idToPerson.getClass().getName()
+ + idToPerson);
+
+ Stream locales = Stream.of(Locale.getAvailableLocales());
+ Map languageNames = locales.collect(
+ Collectors.toMap(
+ Locale::getDisplayLanguage,
+ l -> l.getDisplayLanguage(l),
+ (existingValue, newValue) -> existingValue));
+ System.out.println("languageNames: " + languageNames);
+
+ locales = Stream.of(Locale.getAvailableLocales());
+ Map> countryLanguageSets = locales.collect(
+ Collectors.toMap(
+ Locale::getDisplayCountry,
+ l -> Collections.singleton(l.getDisplayLanguage()),
+ (a, b) -> { // union of a and b
+ Set union = new HashSet<>(a);
+ union.addAll(b);
+ return union;
+ }));
+ System.out.println("countryLanguageSets: " + countryLanguageSets);
+ }
+}
diff --git a/corejava第10版/v2ch01/collecting/CollectingResults.java b/corejava第10版/v2ch01/collecting/CollectingResults.java
new file mode 100644
index 0000000..7762cd9
--- /dev/null
+++ b/corejava第10版/v2ch01/collecting/CollectingResults.java
@@ -0,0 +1,79 @@
+package collecting;
+
+import java.io.*;
+import java.nio.charset.*;
+import java.nio.file.*;
+import java.util.*;
+import java.util.stream.*;
+
+public class CollectingResults
+{
+ public static Stream noVowels() throws IOException
+ {
+ String contents = new String(Files.readAllBytes(
+ Paths.get("../gutenberg/alice30.txt")),
+ StandardCharsets.UTF_8);
+ List wordList = Arrays.asList(contents.split("\\PL+"));
+ Stream words = wordList.stream();
+ return words.map(s -> s.replaceAll("[aeiouAEIOU]", ""));
+ }
+
+ public static void show(String label, Set set)
+ {
+ System.out.print(label + ": " + set.getClass().getName());
+ System.out.println("["
+ + set.stream().limit(10).map(Object::toString)
+ .collect(Collectors.joining(", ")) + "]");
+ }
+
+ public static void main(String[] args) throws IOException
+ {
+ Iterator iter = Stream.iterate(0, n -> n + 1).limit(10)
+ .iterator();
+ while (iter.hasNext())
+ System.out.println(iter.next());
+
+ Object[] numbers = Stream.iterate(0, n -> n + 1).limit(10).toArray();
+ System.out.println("Object array:" + numbers); // Note it's an Object[] array
+
+ try
+ {
+ Integer number = (Integer) numbers[0]; // OK
+ System.out.println("number: " + number);
+ System.out.println("The following statement throws an exception:");
+ Integer[] numbers2 = (Integer[]) numbers; // Throws exception
+ }
+ catch (ClassCastException ex)
+ {
+ System.out.println(ex);
+ }
+
+ Integer[] numbers3 = Stream.iterate(0, n -> n + 1).limit(10)
+ .toArray(Integer[]::new);
+ System.out.println("Integer array: " + numbers3); // Note it's an Integer[] array
+
+ Set noVowelSet = noVowels()
+ .collect(Collectors.toSet());
+ show("noVowelSet", noVowelSet);
+
+ TreeSet noVowelTreeSet = noVowels().collect(
+ Collectors.toCollection(TreeSet::new));
+ show("noVowelTreeSet", noVowelTreeSet);
+
+ String result = noVowels().limit(10).collect(
+ Collectors.joining());
+ System.out.println("Joining: " + result);
+ result = noVowels().limit(10)
+ .collect(Collectors.joining(", "));
+ System.out.println("Joining with commas: " + result);
+
+ IntSummaryStatistics summary = noVowels().collect(
+ Collectors.summarizingInt(String::length));
+ double averageWordLength = summary.getAverage();
+ double maxWordLength = summary.getMax();
+ System.out.println("Average word length: " + averageWordLength);
+ System.out.println("Max word length: " + maxWordLength);
+ System.out.println("forEach:");
+ noVowels().limit(10).forEach(System.out::println);
+ }
+}
diff --git a/corejava第10版/v2ch01/collecting/DownstreamCollectors.java b/corejava第10版/v2ch01/collecting/DownstreamCollectors.java
new file mode 100644
index 0000000..3c84067
--- /dev/null
+++ b/corejava第10版/v2ch01/collecting/DownstreamCollectors.java
@@ -0,0 +1,98 @@
+package collecting;
+
+import static java.util.stream.Collectors.*;
+
+import java.io.*;
+import java.nio.file.*;
+import java.util.*;
+import java.util.stream.*;
+
+public class DownstreamCollectors
+{
+
+ public static class City
+ {
+ private String name;
+ private String state;
+ private int population;
+
+ public City(String name, String state, int population)
+ {
+ this.name = name;
+ this.state = state;
+ this.population = population;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public String getState()
+ {
+ return state;
+ }
+
+ public int getPopulation()
+ {
+ return population;
+ }
+ }
+
+ public static Stream readCities(String filename) throws IOException
+ {
+ return Files.lines(Paths.get(filename)).map(l -> l.split(", "))
+ .map(a -> new City(a[0], a[1], Integer.parseInt(a[2])));
+ }
+
+ public static void main(String[] args) throws IOException
+ {
+ Stream locales = Stream.of(Locale.getAvailableLocales());
+ locales = Stream.of(Locale.getAvailableLocales());
+ Map> countryToLocaleSet = locales.collect(groupingBy(
+ Locale::getCountry, toSet()));
+ System.out.println("countryToLocaleSet: " + countryToLocaleSet);
+
+ locales = Stream.of(Locale.getAvailableLocales());
+ Map countryToLocaleCounts = locales.collect(groupingBy(
+ Locale::getCountry, counting()));
+ System.out.println("countryToLocaleCounts: " + countryToLocaleCounts);
+
+ Stream cities = readCities("cities.txt");
+ Map stateToCityPopulation = cities.collect(groupingBy(
+ City::getState, summingInt(City::getPopulation)));
+ System.out.println("stateToCityPopulation: " + stateToCityPopulation);
+
+ cities = readCities("cities.txt");
+ Map> stateToLongestCityName = cities
+ .collect(groupingBy(
+ City::getState,
+ mapping(City::getName,
+ maxBy(Comparator.comparing(String::length)))));
+
+ System.out.println("stateToLongestCityName: " + stateToLongestCityName);
+
+ locales = Stream.of(Locale.getAvailableLocales());
+ Map> countryToLanguages = locales.collect(groupingBy(
+ Locale::getDisplayCountry,
+ mapping(Locale::getDisplayLanguage, toSet())));
+ System.out.println("countryToLanguages: " + countryToLanguages);
+
+ cities = readCities("cities.txt");
+ Map stateToCityPopulationSummary = cities
+ .collect(groupingBy(City::getState,
+ summarizingInt(City::getPopulation)));
+ System.out.println(stateToCityPopulationSummary.get("NY"));
+
+ cities = readCities("cities.txt");
+ Map stateToCityNames = cities.collect(groupingBy(
+ City::getState,
+ reducing("", City::getName, (s, t) -> s.length() == 0 ? t : s
+ + ", " + t)));
+
+ cities = readCities("cities.txt");
+ stateToCityNames = cities.collect(groupingBy(City::getState,
+ mapping(City::getName, joining(", "))));
+ System.out.println("stateToCityNames: " + stateToCityNames);
+ }
+}
diff --git a/corejava第10版/v2ch01/optional/OptionalTest.java b/corejava第10版/v2ch01/optional/OptionalTest.java
new file mode 100644
index 0000000..863d74b
--- /dev/null
+++ b/corejava第10版/v2ch01/optional/OptionalTest.java
@@ -0,0 +1,63 @@
+package optional;
+
+import java.io.*;
+import java.nio.charset.*;
+import java.nio.file.*;
+import java.util.*;
+
+public class OptionalTest
+{
+ public static void main(String[] args) throws IOException
+ {
+ String contents = new String(Files.readAllBytes(
+ Paths.get("../gutenberg/alice30.txt")), StandardCharsets.UTF_8);
+ List wordList = Arrays.asList(contents.split("\\PL+"));
+
+ Optional optionalValue = wordList.stream()
+ .filter(s -> s.contains("fred"))
+ .findFirst();
+ System.out.println(optionalValue.orElse("No word") + " contains fred");
+
+ Optional optionalString = Optional.empty();
+ String result = optionalString.orElse("N/A");
+ System.out.println("result: " + result);
+ result = optionalString.orElseGet(() -> Locale.getDefault().getDisplayName());
+ System.out.println("result: " + result);
+ try
+ {
+ result = optionalString.orElseThrow(IllegalStateException::new);
+ System.out.println("result: " + result);
+ }
+ catch (Throwable t)
+ {
+ t.printStackTrace();
+ }
+
+ optionalValue = wordList.stream()
+ .filter(s -> s.contains("red"))
+ .findFirst();
+ optionalValue.ifPresent(s -> System.out.println(s + " contains red"));
+
+ Set results = new HashSet<>();
+ optionalValue.ifPresent(results::add);
+ Optional added = optionalValue.map(results::add);
+ System.out.println(added);
+
+ System.out.println(inverse(4.0).flatMap(OptionalTest::squareRoot));
+ System.out.println(inverse(-1.0).flatMap(OptionalTest::squareRoot));
+ System.out.println(inverse(0.0).flatMap(OptionalTest::squareRoot));
+ Optional result2 = Optional.of(-4.0)
+ .flatMap(OptionalTest::inverse).flatMap(OptionalTest::squareRoot);
+ System.out.println(result2);
+ }
+
+ public static Optional inverse(Double x)
+ {
+ return x == 0 ? Optional.empty() : Optional.of(1 / x);
+ }
+
+ public static Optional squareRoot(Double x)
+ {
+ return x < 0 ? Optional.empty() : Optional.of(Math.sqrt(x));
+ }
+}
diff --git a/corejava第10版/v2ch01/parallel/ParallelStreams.java b/corejava第10版/v2ch01/parallel/ParallelStreams.java
new file mode 100644
index 0000000..2c04662
--- /dev/null
+++ b/corejava第10版/v2ch01/parallel/ParallelStreams.java
@@ -0,0 +1,58 @@
+package parallel;
+
+import static java.util.stream.Collectors.*;
+
+import java.io.*;
+import java.nio.charset.*;
+import java.nio.file.*;
+import java.util.*;
+import java.util.stream.*;
+
+public class ParallelStreams
+{
+ public static void main(String[] args) throws IOException
+ {
+ String contents = new String(Files.readAllBytes(
+ Paths.get("../gutenberg/alice30.txt")), StandardCharsets.UTF_8);
+ List wordList = Arrays.asList(contents.split("\\PL+"));
+
+ // Very bad code ahead
+ int[] shortWords = new int[10];
+ wordList.parallelStream().forEach(s ->
+ {
+ if (s.length() < 10) shortWords[s.length()]++;
+ });
+ System.out.println(Arrays.toString(shortWords));
+
+ // Try again--the result will likely be different (and also wrong)
+ Arrays.fill(shortWords, 0);
+ wordList.parallelStream().forEach(s ->
+ {
+ if (s.length() < 10) shortWords[s.length()]++;
+ });
+ System.out.println(Arrays.toString(shortWords));
+
+ // Remedy: Group and count
+ Map shortWordCounts = wordList.parallelStream()
+ .filter(s -> s.length() < 10)
+ .collect(groupingBy(String::length, counting()));
+
+ System.out.println(shortWordCounts);
+
+ // Downstream order not deterministic
+ Map> result = wordList.parallelStream().collect(
+ Collectors.groupingByConcurrent(String::length));
+
+ System.out.println(result.get(14));
+
+ result = wordList.parallelStream().collect(
+ Collectors.groupingByConcurrent(String::length));
+
+ System.out.println(result.get(14));
+
+ Map wordCounts = wordList.parallelStream().collect(
+ groupingByConcurrent(String::length, counting()));
+
+ System.out.println(wordCounts);
+ }
+}
diff --git a/corejava第10版/v2ch01/streams/CountLongWords.java b/corejava第10版/v2ch01/streams/CountLongWords.java
new file mode 100644
index 0000000..e0366c4
--- /dev/null
+++ b/corejava第10版/v2ch01/streams/CountLongWords.java
@@ -0,0 +1,31 @@
+package streams;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+
+public class CountLongWords
+{
+ public static void main(String[] args) throws IOException
+ {
+ String contents = new String(Files.readAllBytes(
+ Paths.get("../gutenberg/alice30.txt")), StandardCharsets.UTF_8);
+ List words = Arrays.asList(contents.split("\\PL+"));
+
+ long count = 0;
+ for (String w : words)
+ {
+ if (w.length() > 12) count++;
+ }
+ System.out.println(count);
+
+ count = words.stream().filter(w -> w.length() > 12).count();
+ System.out.println(count);
+
+ count = words.parallelStream().filter(w -> w.length() > 12).count();
+ System.out.println(count);
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch01/streams/CreatingStreams.java b/corejava第10版/v2ch01/streams/CreatingStreams.java
new file mode 100644
index 0000000..e2477cd
--- /dev/null
+++ b/corejava第10版/v2ch01/streams/CreatingStreams.java
@@ -0,0 +1,64 @@
+package streams;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+public class CreatingStreams
+{
+ public static void show(String title, Stream stream)
+ {
+ final int SIZE = 10;
+ List firstElements = stream
+ .limit(SIZE + 1)
+ .collect(Collectors.toList());
+ System.out.print(title + ": ");
+ for (int i = 0; i < firstElements.size(); i++)
+ {
+ if (i > 0) System.out.print(", ");
+ if (i < SIZE) System.out.print(firstElements.get(i));
+ else System.out.print("...");
+ }
+ System.out.println();
+ }
+
+ public static void main(String[] args) throws IOException
+ {
+ Path path = Paths.get("../gutenberg/alice30.txt");
+ String contents = new String(Files.readAllBytes(path),
+ StandardCharsets.UTF_8);
+
+ Stream words = Stream.of(contents.split("\\PL+"));
+ show("words", words);
+ Stream song = Stream.of("gently", "down", "the", "stream");
+ show("song", song);
+ Stream silence = Stream.empty();
+ show("silence", silence);
+
+ Stream echos = Stream.generate(() -> "Echo");
+ show("echos", echos);
+
+ Stream randoms = Stream.generate(Math::random);
+ show("randoms", randoms);
+
+ Stream integers = Stream.iterate(BigInteger.ONE,
+ n -> n.add(BigInteger.ONE));
+ show("integers", integers);
+
+ Stream wordsAnotherWay = Pattern.compile("\\PL+").splitAsStream(
+ contents);
+ show("wordsAnotherWay", wordsAnotherWay);
+
+ try (Stream lines = Files.lines(path, StandardCharsets.UTF_8))
+ {
+ show("lines", lines);
+ }
+ }
+}
diff --git a/corejava第10版/v2ch01/streams/PrimitiveTypeStreams.java b/corejava第10版/v2ch01/streams/PrimitiveTypeStreams.java
new file mode 100644
index 0000000..e4c7a35
--- /dev/null
+++ b/corejava第10版/v2ch01/streams/PrimitiveTypeStreams.java
@@ -0,0 +1,53 @@
+package streams;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+public class PrimitiveTypeStreams
+{
+ public static void show(String title, IntStream stream)
+ {
+ final int SIZE = 10;
+ int[] firstElements = stream.limit(SIZE + 1).toArray();
+ System.out.print(title + ": ");
+ for (int i = 0; i < firstElements.length; i++)
+ {
+ if (i > 0) System.out.print(", ");
+ if (i < SIZE) System.out.print(firstElements[i]);
+ else System.out.print("...");
+ }
+ System.out.println();
+ }
+
+ public static void main(String[] args) throws IOException
+ {
+ IntStream is1 = IntStream.generate(() -> (int) (Math.random() * 100));
+ show("is1", is1);
+ IntStream is2 = IntStream.range(5, 10);
+ show("is2", is2);
+ IntStream is3 = IntStream.rangeClosed(5, 10);
+ show("is3", is3);
+
+ Path path = Paths.get("../gutenberg/alice30.txt");
+ String contents = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
+
+ Stream words = Stream.of(contents.split("\\PL+"));
+ IntStream is4 = words.mapToInt(String::length);
+ show("is4", is4);
+ String sentence = "\uD835\uDD46 is the set of octonions.";
+ System.out.println(sentence);
+ IntStream codes = sentence.codePoints();
+ System.out.println(codes.mapToObj(c -> String.format("%X ", c)).collect(
+ Collectors.joining()));
+
+ Stream integers = IntStream.range(0, 100).boxed();
+ IntStream is5 = integers.mapToInt(Integer::intValue);
+ show("is5", is5);
+ }
+}
diff --git a/javacore第11版/corejava/v2ch02/employee.dat b/corejava第10版/v2ch02/employee.dat
similarity index 100%
rename from javacore第11版/corejava/v2ch02/employee.dat
rename to corejava第10版/v2ch02/employee.dat
diff --git a/javacore第11版/corejava/v2ch02/employee2.dat b/corejava第10版/v2ch02/employee2.dat
similarity index 100%
rename from javacore第11版/corejava/v2ch02/employee2.dat
rename to corejava第10版/v2ch02/employee2.dat
diff --git a/javacore第11版/corejava/v2ch02/employee3.dat b/corejava第10版/v2ch02/employee3.dat
similarity index 100%
rename from javacore第11版/corejava/v2ch02/employee3.dat
rename to corejava第10版/v2ch02/employee3.dat
diff --git a/corejava第10版/v2ch02/findDirectories/FindDirectories.java b/corejava第10版/v2ch02/findDirectories/FindDirectories.java
new file mode 100644
index 0000000..351cc4c
--- /dev/null
+++ b/corejava第10版/v2ch02/findDirectories/FindDirectories.java
@@ -0,0 +1,30 @@
+package findDirectories;
+
+import java.io.*;
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+
+/**
+ * @version 1.1 2012-05-31
+ * @author Cay Horstmann
+ */
+public class FindDirectories
+{
+ public static void main(String[] args) throws IOException
+ {
+ Path dir = Paths.get(args.length == 0 ? System.getProperty("user.home") : args[0]);
+ Files.walkFileTree(dir, new SimpleFileVisitor()
+ {
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException
+ {
+ if (attrs.isDirectory())
+ System.out.println(file);
+ return FileVisitResult.CONTINUE;
+ }
+ public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException
+ {
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ }
+}
diff --git a/corejava第10版/v2ch02/match/HrefMatch.java b/corejava第10版/v2ch02/match/HrefMatch.java
new file mode 100644
index 0000000..18067ef
--- /dev/null
+++ b/corejava第10版/v2ch02/match/HrefMatch.java
@@ -0,0 +1,52 @@
+package match;
+
+import java.io.*;
+import java.net.*;
+import java.nio.charset.*;
+import java.util.regex.*;
+
+/**
+ * This program displays all URLs in a web page by matching a regular expression that describes the
+ * HTML tag. Start the program as
+ * java match.HrefMatch URL
+ * @version 1.02 2016-07-14
+ * @author Cay Horstmann
+ */
+public class HrefMatch
+{
+ public static void main(String[] args)
+ {
+ try
+ {
+ // get URL string from command line or use default
+ String urlString;
+ if (args.length > 0) urlString = args[0];
+ else urlString = "http://java.sun.com";
+
+ // open reader for URL
+ InputStreamReader in = new InputStreamReader(new URL(urlString).openStream(),
+ StandardCharsets.UTF_8);
+
+ // read contents into string builder
+ StringBuilder input = new StringBuilder();
+ int ch;
+ while ((ch = in.read()) != -1)
+ input.append((char) ch);
+
+ // search for all occurrences of pattern
+ String patternString = " ]*)\\s*>";
+ Pattern pattern = Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);
+ Matcher matcher = pattern.matcher(input);
+
+ while (matcher.find())
+ {
+ String match = matcher.group();
+ System.out.println(match);
+ }
+ }
+ catch (IOException | PatternSyntaxException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/corejava第10版/v2ch02/memoryMap/MemoryMapTest.java b/corejava第10版/v2ch02/memoryMap/MemoryMapTest.java
new file mode 100644
index 0000000..e6e0cb3
--- /dev/null
+++ b/corejava第10版/v2ch02/memoryMap/MemoryMapTest.java
@@ -0,0 +1,108 @@
+package memoryMap;
+
+import java.io.*;
+import java.nio.*;
+import java.nio.channels.*;
+import java.nio.file.*;
+import java.util.zip.*;
+
+/**
+ * This program computes the CRC checksum of a file in four ways.
+ * Usage: java memoryMap.MemoryMapTest filename
+ * @version 1.01 2012-05-30
+ * @author Cay Horstmann
+ */
+public class MemoryMapTest
+{
+ public static long checksumInputStream(Path filename) throws IOException
+ {
+ try (InputStream in = Files.newInputStream(filename))
+ {
+ CRC32 crc = new CRC32();
+
+ int c;
+ while ((c = in.read()) != -1)
+ crc.update(c);
+ return crc.getValue();
+ }
+ }
+
+ public static long checksumBufferedInputStream(Path filename) throws IOException
+ {
+ try (InputStream in = new BufferedInputStream(Files.newInputStream(filename)))
+ {
+ CRC32 crc = new CRC32();
+
+ int c;
+ while ((c = in.read()) != -1)
+ crc.update(c);
+ return crc.getValue();
+ }
+ }
+
+ public static long checksumRandomAccessFile(Path filename) throws IOException
+ {
+ try (RandomAccessFile file = new RandomAccessFile(filename.toFile(), "r"))
+ {
+ long length = file.length();
+ CRC32 crc = new CRC32();
+
+ for (long p = 0; p < length; p++)
+ {
+ file.seek(p);
+ int c = file.readByte();
+ crc.update(c);
+ }
+ return crc.getValue();
+ }
+ }
+
+ public static long checksumMappedFile(Path filename) throws IOException
+ {
+ try (FileChannel channel = FileChannel.open(filename))
+ {
+ CRC32 crc = new CRC32();
+ int length = (int) channel.size();
+ MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, length);
+
+ for (int p = 0; p < length; p++)
+ {
+ int c = buffer.get(p);
+ crc.update(c);
+ }
+ return crc.getValue();
+ }
+ }
+
+ public static void main(String[] args) throws IOException
+ {
+ System.out.println("Input Stream:");
+ long start = System.currentTimeMillis();
+ Path filename = Paths.get(args[0]);
+ long crcValue = checksumInputStream(filename);
+ long end = System.currentTimeMillis();
+ System.out.println(Long.toHexString(crcValue));
+ System.out.println((end - start) + " milliseconds");
+
+ System.out.println("Buffered Input Stream:");
+ start = System.currentTimeMillis();
+ crcValue = checksumBufferedInputStream(filename);
+ end = System.currentTimeMillis();
+ System.out.println(Long.toHexString(crcValue));
+ System.out.println((end - start) + " milliseconds");
+
+ System.out.println("Random Access File:");
+ start = System.currentTimeMillis();
+ crcValue = checksumRandomAccessFile(filename);
+ end = System.currentTimeMillis();
+ System.out.println(Long.toHexString(crcValue));
+ System.out.println((end - start) + " milliseconds");
+
+ System.out.println("Mapped File:");
+ start = System.currentTimeMillis();
+ crcValue = checksumMappedFile(filename);
+ end = System.currentTimeMillis();
+ System.out.println(Long.toHexString(crcValue));
+ System.out.println((end - start) + " milliseconds");
+ }
+}
diff --git a/corejava第10版/v2ch02/memoryMap/MemoryMapTest2.java b/corejava第10版/v2ch02/memoryMap/MemoryMapTest2.java
new file mode 100644
index 0000000..ba2e40b
--- /dev/null
+++ b/corejava第10版/v2ch02/memoryMap/MemoryMapTest2.java
@@ -0,0 +1,115 @@
+package memoryMap;
+
+import java.io.*;
+import java.nio.*;
+import java.nio.channels.*;
+import java.nio.file.*;
+import java.util.zip.*;
+
+/**
+ * This program computes the CRC checksum of a file in four ways.
+ * Usage: java memoryMap.MemoryMapTest filename
+ * @version 1.01 2012-05-30
+ * @author Cay Horstmann
+ */
+public class MemoryMapTest2
+{
+ public static int BLOCK_SIZE = 1024;
+
+ public static long checksumInputStream(Path filename) throws IOException
+ {
+ try (InputStream in = Files.newInputStream(filename))
+ {
+ CRC32 crc = new CRC32();
+
+ byte[] bytes = new byte[BLOCK_SIZE];
+ int n;
+ while ((n = in.read(bytes)) != -1)
+ crc.update(bytes, 0, n);
+ return crc.getValue();
+ }
+ }
+
+ public static long checksumBufferedInputStream(Path filename) throws IOException
+ {
+ try (InputStream in = new BufferedInputStream(Files.newInputStream(filename)))
+ {
+ CRC32 crc = new CRC32();
+
+ byte[] bytes = new byte[BLOCK_SIZE];
+ int n;
+ while ((n = in.read(bytes)) != -1)
+ crc.update(bytes, 0, n);
+ return crc.getValue();
+ }
+ }
+
+ public static long checksumRandomAccessFile(Path filename) throws IOException
+ {
+ try (RandomAccessFile file = new RandomAccessFile(filename.toFile(), "r"))
+ {
+ long length = file.length();
+ CRC32 crc = new CRC32();
+
+ byte[] bytes = new byte[BLOCK_SIZE];
+ for (long p = 0; p < length; p += BLOCK_SIZE)
+ {
+ file.seek(p);
+ int n = file.read(bytes);
+ crc.update(bytes, 0, n);
+ }
+ return crc.getValue();
+ }
+ }
+
+ public static long checksumMappedFile(Path filename) throws IOException
+ {
+ try (FileChannel channel = FileChannel.open(filename))
+ {
+ CRC32 crc = new CRC32();
+ int length = (int) channel.size();
+ MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, length);
+
+ byte[] bytes = new byte[BLOCK_SIZE];
+ for (int p = 0; p < length; p += BLOCK_SIZE)
+ {
+ int n = Math.min(BLOCK_SIZE, length - p);
+ buffer.get(bytes, 0, n);
+ crc.update(bytes, 0, n);
+ }
+ return crc.getValue();
+ }
+ }
+
+ public static void main(String[] args) throws IOException
+ {
+ System.out.println("Input Stream:");
+ long start = System.currentTimeMillis();
+ Path filename = Paths.get(args[0]);
+ long crcValue = checksumInputStream(filename);
+ long end = System.currentTimeMillis();
+ System.out.println(Long.toHexString(crcValue));
+ System.out.println((end - start) + " milliseconds");
+
+ System.out.println("Buffered Input Stream:");
+ start = System.currentTimeMillis();
+ crcValue = checksumBufferedInputStream(filename);
+ end = System.currentTimeMillis();
+ System.out.println(Long.toHexString(crcValue));
+ System.out.println((end - start) + " milliseconds");
+
+ System.out.println("Random Access File:");
+ start = System.currentTimeMillis();
+ crcValue = checksumRandomAccessFile(filename);
+ end = System.currentTimeMillis();
+ System.out.println(Long.toHexString(crcValue));
+ System.out.println((end - start) + " milliseconds");
+
+ System.out.println("Mapped File:");
+ start = System.currentTimeMillis();
+ crcValue = checksumMappedFile(filename);
+ end = System.currentTimeMillis();
+ System.out.println(Long.toHexString(crcValue));
+ System.out.println((end - start) + " milliseconds");
+ }
+}
diff --git a/javacore第11版/corejava/v2ch02/objectStream/Employee.java b/corejava第10版/v2ch02/objectStream/Employee.java
similarity index 100%
rename from javacore第11版/corejava/v2ch02/objectStream/Employee.java
rename to corejava第10版/v2ch02/objectStream/Employee.java
diff --git a/javacore第11版/corejava/v2ch02/objectStream/Manager.java b/corejava第10版/v2ch02/objectStream/Manager.java
similarity index 100%
rename from javacore第11版/corejava/v2ch02/objectStream/Manager.java
rename to corejava第10版/v2ch02/objectStream/Manager.java
diff --git a/corejava第10版/v2ch02/objectStream/ObjectStreamTest.java b/corejava第10版/v2ch02/objectStream/ObjectStreamTest.java
new file mode 100644
index 0000000..8fea29f
--- /dev/null
+++ b/corejava第10版/v2ch02/objectStream/ObjectStreamTest.java
@@ -0,0 +1,45 @@
+package objectStream;
+
+import java.io.*;
+
+/**
+ * @version 1.10 17 Aug 1998
+ * @author Cay Horstmann
+ */
+class ObjectStreamTest
+{
+ public static void main(String[] args) throws IOException, ClassNotFoundException
+ {
+ Employee harry = new Employee("Harry Hacker", 50000, 1989, 10, 1);
+ Manager carl = new Manager("Carl Cracker", 80000, 1987, 12, 15);
+ carl.setSecretary(harry);
+ Manager tony = new Manager("Tony Tester", 40000, 1990, 3, 15);
+ tony.setSecretary(harry);
+
+ Employee[] staff = new Employee[3];
+
+ staff[0] = carl;
+ staff[1] = harry;
+ staff[2] = tony;
+
+ // save all employee records to the file employee.dat
+ try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("employee.dat")))
+ {
+ out.writeObject(staff);
+ }
+
+ try (ObjectInputStream in = new ObjectInputStream(new FileInputStream("employee.dat")))
+ {
+ // retrieve all records into a new array
+
+ Employee[] newStaff = (Employee[]) in.readObject();
+
+ // raise secretary's salary
+ newStaff[1].raiseSalary(10);
+
+ // print the newly read employee records
+ for (Employee e : newStaff)
+ System.out.println(e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v2ch02/objectStream/employee.dat b/corejava第10版/v2ch02/objectStream/employee.dat
similarity index 100%
rename from javacore第11版/corejava/v2ch02/objectStream/employee.dat
rename to corejava第10版/v2ch02/objectStream/employee.dat
diff --git a/corejava第10版/v2ch02/randomAccess/DataIO.java b/corejava第10版/v2ch02/randomAccess/DataIO.java
new file mode 100644
index 0000000..2a8b3a2
--- /dev/null
+++ b/corejava第10版/v2ch02/randomAccess/DataIO.java
@@ -0,0 +1,34 @@
+package randomAccess;
+
+import java.io.*;
+
+public class DataIO
+{
+ public static String readFixedString(int size, DataInput in)
+ throws IOException
+ {
+ StringBuilder b = new StringBuilder(size);
+ int i = 0;
+ boolean more = true;
+ while (more && i < size)
+ {
+ char ch = in.readChar();
+ i++;
+ if (ch == 0) more = false;
+ else b.append(ch);
+ }
+ in.skipBytes(2 * (size - i));
+ return b.toString();
+ }
+
+ public static void writeFixedString(String s, int size, DataOutput out)
+ throws IOException
+ {
+ for (int i = 0; i < size; i++)
+ {
+ char ch = 0;
+ if (i < s.length()) ch = s.charAt(i);
+ out.writeChar(ch);
+ }
+ }
+}
diff --git a/javacore第11版/corejava/v2ch02/randomAccess/Employee.java b/corejava第10版/v2ch02/randomAccess/Employee.java
similarity index 100%
rename from javacore第11版/corejava/v2ch02/randomAccess/Employee.java
rename to corejava第10版/v2ch02/randomAccess/Employee.java
diff --git a/corejava第10版/v2ch02/randomAccess/RandomAccessTest.java b/corejava第10版/v2ch02/randomAccess/RandomAccessTest.java
new file mode 100644
index 0000000..17eeec4
--- /dev/null
+++ b/corejava第10版/v2ch02/randomAccess/RandomAccessTest.java
@@ -0,0 +1,80 @@
+package randomAccess;
+
+import java.io.*;
+import java.util.*;
+import java.time.*;
+
+/**
+ * @version 1.13 2016-07-11
+ * @author Cay Horstmann
+ */
+public class RandomAccessTest
+{
+ public static void main(String[] args) throws IOException
+ {
+ Employee[] staff = new Employee[3];
+
+ staff[0] = new Employee("Carl Cracker", 75000, 1987, 12, 15);
+ staff[1] = new Employee("Harry Hacker", 50000, 1989, 10, 1);
+ staff[2] = new Employee("Tony Tester", 40000, 1990, 3, 15);
+
+ try (DataOutputStream out = new DataOutputStream(new FileOutputStream("employee.dat")))
+ {
+ // save all employee records to the file employee.dat
+ for (Employee e : staff)
+ writeData(out, e);
+ }
+
+ try (RandomAccessFile in = new RandomAccessFile("employee.dat", "r"))
+ {
+ // retrieve all records into a new array
+
+ // compute the array size
+ int n = (int)(in.length() / Employee.RECORD_SIZE);
+ Employee[] newStaff = new Employee[n];
+
+ // read employees in reverse order
+ for (int i = n - 1; i >= 0; i--)
+ {
+ newStaff[i] = new Employee();
+ in.seek(i * Employee.RECORD_SIZE);
+ newStaff[i] = readData(in);
+ }
+
+ // print the newly read employee records
+ for (Employee e : newStaff)
+ System.out.println(e);
+ }
+ }
+
+ /**
+ * Writes employee data to a data output
+ * @param out the data output
+ * @param e the employee
+ */
+ public static void writeData(DataOutput out, Employee e) throws IOException
+ {
+ DataIO.writeFixedString(e.getName(), Employee.NAME_SIZE, out);
+ out.writeDouble(e.getSalary());
+
+ LocalDate hireDay = e.getHireDay();
+ out.writeInt(hireDay.getYear());
+ out.writeInt(hireDay.getMonthValue());
+ out.writeInt(hireDay.getDayOfMonth());
+ }
+
+ /**
+ * Reads employee data from a data input
+ * @param in the data input
+ * @return the employee
+ */
+ public static Employee readData(DataInput in) throws IOException
+ {
+ String name = DataIO.readFixedString(Employee.NAME_SIZE, in);
+ double salary = in.readDouble();
+ int y = in.readInt();
+ int m = in.readInt();
+ int d = in.readInt();
+ return new Employee(name, salary, y, m - 1, d);
+ }
+}
diff --git a/corejava第10版/v2ch02/randomAccess2/Employee.java b/corejava第10版/v2ch02/randomAccess2/Employee.java
new file mode 100644
index 0000000..6258571
--- /dev/null
+++ b/corejava第10版/v2ch02/randomAccess2/Employee.java
@@ -0,0 +1,57 @@
+package randomAccess2;
+
+import java.util.*;
+
+public class Employee
+{
+ public static final int NAME_SIZE = 40;
+ public static final int RECORD_SIZE = 2 * NAME_SIZE + 8 + 4 + 4 + 4;
+
+ private String name;
+ private double salary;
+ private Date hireDay;
+
+ public 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;
+ }
+
+ /**
+ Raises the salary of this employee.
+ @byPercent the percentage of the raise
+ */
+ public void raiseSalary(double byPercent)
+ {
+ double raise = salary * byPercent / 100;
+ salary += raise;
+ }
+
+ public String toString()
+ {
+ return getClass().getName()
+ + "[name=" + name
+ + ",salary=" + salary
+ + ",hireDay=" + hireDay
+ + "]";
+ }
+}
diff --git a/corejava第10版/v2ch02/randomAccess2/RandomAccessTest.java b/corejava第10版/v2ch02/randomAccess2/RandomAccessTest.java
new file mode 100644
index 0000000..511afa5
--- /dev/null
+++ b/corejava第10版/v2ch02/randomAccess2/RandomAccessTest.java
@@ -0,0 +1,100 @@
+package randomAccess2;
+
+import java.io.*;
+import java.nio.*;
+import java.nio.channels.*;
+import java.nio.file.*;
+import java.util.*;
+
+/**
+ * @version 1.12 2012-05-30
+ * @author Cay Horstmann
+ */
+public class RandomAccessTest
+{
+ public static void main(String[] args) throws IOException
+ {
+ Employee[] staff = new Employee[3];
+
+ staff[0] = new Employee("Carl Cracker", 75000, 1987, 12, 15);
+ staff[1] = new Employee("Harry Hacker", 50000, 1989, 10, 1);
+ staff[2] = new Employee("Tony Tester", 40000, 1990, 3, 15);
+
+ Path path = Paths.get("employee.dat");
+ ByteBuffer buffer = ByteBuffer.allocate(Employee.RECORD_SIZE);
+
+ try (FileChannel channel = FileChannel.open(path,
+ StandardOpenOption.CREATE, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING))
+ {
+ // save all employee records to the file employee.dat
+ for (Employee e : staff)
+ {
+ buffer.clear();
+ writeData(buffer, e);
+ buffer.flip();
+ channel.write(buffer);
+ }
+ }
+
+ try (FileChannel channel = FileChannel.open(path, StandardOpenOption.READ))
+ {
+ // compute the array size
+ int n = (int)(Files.size(path)) / Employee.RECORD_SIZE;
+ Employee[] newStaff = new Employee[n];
+
+ // read employees in reverse order
+ for (int i = n - 1; i >= 0; i--)
+ {
+ newStaff[i] = new Employee();
+ channel.position(i * Employee.RECORD_SIZE);
+ buffer.clear();
+ channel.read(buffer);
+ buffer.flip();
+ newStaff[i] = readData(buffer);
+ }
+
+ // print the newly read employee records
+ for (Employee e : newStaff)
+ System.out.println(e);
+ }
+ }
+
+
+ /**
+ Writes employee data to a byte buffer
+ @param out the buffer
+ @param e the employee
+ */
+ public static void writeData(ByteBuffer out, Employee e) throws IOException
+ {
+ String name = e.getName();
+ int length = Math.min(name.length(), Employee.NAME_SIZE - 1);
+ // for (int i = 0; i < length; i++) out.putChar(name.charAt(i));
+ out.asCharBuffer().put(name.substring(0, length)).put('\0');
+ out.position(2 * Employee.NAME_SIZE);
+ out.putDouble(e.getSalary());
+ GregorianCalendar calendar = new GregorianCalendar();
+ calendar.setTime(e.getHireDay());
+ out.putInt(calendar.get(Calendar.YEAR));
+ out.putInt(calendar.get(Calendar.MONTH) + 1);
+ out.putInt(calendar.get(Calendar.DAY_OF_MONTH));
+ }
+
+ /**
+ Reads employee data from a byte buffer
+ @param in the buffer
+ @return the employee
+ */
+ public static Employee readData(ByteBuffer in) throws IOException
+ {
+ StringBuilder name = new StringBuilder();
+ char ch;
+ while ((ch = in.getChar()) != '\0') name.append(ch);
+ in.position(2 * Employee.NAME_SIZE);
+ double salary = in.getDouble();
+ int y = in.getInt();
+ int m = in.getInt();
+ int d = in.getInt();
+ return new Employee(name.toString(), salary, y, m - 1, d);
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch02/regex/RegexTest.java b/corejava第10版/v2ch02/regex/RegexTest.java
new file mode 100644
index 0000000..ea94339
--- /dev/null
+++ b/corejava第10版/v2ch02/regex/RegexTest.java
@@ -0,0 +1,58 @@
+package regex;
+
+import java.util.*;
+import java.util.regex.*;
+
+/**
+ * This program tests regular expression matching. Enter a pattern and strings to match,
+ * or hit Cancel to exit. If the pattern contains groups, the group boundaries are displayed
+ * in the match.
+ * @version 1.02 2012-06-02
+ * @author Cay Horstmann
+ */
+public class RegexTest
+{
+ public static void main(String[] args) throws PatternSyntaxException
+ {
+ Scanner in = new Scanner(System.in);
+ System.out.println("Enter pattern: ");
+ String patternString = in.nextLine();
+
+ Pattern pattern = Pattern.compile(patternString);
+
+ while (true)
+ {
+ System.out.println("Enter string to match: ");
+ String input = in.nextLine();
+ if (input == null || input.equals("")) return;
+ Matcher matcher = pattern.matcher(input);
+ if (matcher.matches())
+ {
+ System.out.println("Match");
+ int g = matcher.groupCount();
+ if (g > 0)
+ {
+ for (int i = 0; i < input.length(); i++)
+ {
+ // Print any empty groups
+ for (int j = 1; j <= g; j++)
+ if (i == matcher.start(j) && i == matcher.end(j))
+ System.out.print("()");
+ // Print ( for non-empty groups starting here
+ for (int j = 1; j <= g; j++)
+ if (i == matcher.start(j) && i != matcher.end(j))
+ System.out.print('(');
+ System.out.print(input.charAt(i));
+ // Print ) for non-empty groups ending here
+ for (int j = 1; j <= g; j++)
+ if (i + 1 != matcher.start(j) && i + 1 == matcher.end(j))
+ System.out.print(')');
+ }
+ System.out.println();
+ }
+ }
+ else
+ System.out.println("No match");
+ }
+ }
+}
diff --git a/corejava第10版/v2ch02/serialClone/SerialCloneTest.java b/corejava第10版/v2ch02/serialClone/SerialCloneTest.java
new file mode 100644
index 0000000..12966c9
--- /dev/null
+++ b/corejava第10版/v2ch02/serialClone/SerialCloneTest.java
@@ -0,0 +1,110 @@
+package serialClone;
+
+/**
+ * @version 1.21 13 Jul 2016
+ * @author Cay Horstmann
+ */
+
+import java.io.*;
+import java.util.*;
+import java.time.*;
+
+public class SerialCloneTest
+{
+ public static void main(String[] args) throws CloneNotSupportedException
+ {
+ Employee harry = new Employee("Harry Hacker", 35000, 1989, 10, 1);
+ // clone harry
+ Employee harry2 = (Employee) harry.clone();
+
+ // mutate harry
+ harry.raiseSalary(10);
+
+ // now harry and the clone are different
+ System.out.println(harry);
+ System.out.println(harry2);
+ }
+}
+
+/**
+ * A class whose clone method uses serialization.
+ */
+class SerialCloneable implements Cloneable, Serializable
+{
+ public Object clone() throws CloneNotSupportedException
+ {
+ try {
+ // save the object to a byte array
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ try (ObjectOutputStream out = new ObjectOutputStream(bout))
+ {
+ out.writeObject(this);
+ }
+
+ // read a clone of the object from the byte array
+ try (InputStream bin = new ByteArrayInputStream(bout.toByteArray()))
+ {
+ ObjectInputStream in = new ObjectInputStream(bin);
+ return in.readObject();
+ }
+ }
+ catch (IOException | ClassNotFoundException e)
+ {
+ CloneNotSupportedException e2 = new CloneNotSupportedException();
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+}
+
+/**
+ * The familiar Employee class, redefined to extend the
+ * SerialCloneable class.
+ */
+class Employee extends SerialCloneable
+{
+ private String name;
+ private double salary;
+ private LocalDate hireDay;
+
+ public Employee(String n, double s, int year, int month, int day)
+ {
+ name = n;
+ salary = s;
+ hireDay = LocalDate.of(year, month, day);
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public double getSalary()
+ {
+ return salary;
+ }
+
+ public LocalDate getHireDay()
+ {
+ return hireDay;
+ }
+
+ /**
+ Raises the salary of this employee.
+ @byPercent the percentage of the raise
+ */
+ public void raiseSalary(double byPercent)
+ {
+ double raise = salary * byPercent / 100;
+ salary += raise;
+ }
+
+ public String toString()
+ {
+ return getClass().getName()
+ + "[name=" + name
+ + ",salary=" + salary
+ + ",hireDay=" + hireDay
+ + "]";
+ }
+}
diff --git a/corejava第10版/v2ch02/textFile/Employee.java b/corejava第10版/v2ch02/textFile/Employee.java
new file mode 100644
index 0000000..5f5d478
--- /dev/null
+++ b/corejava第10版/v2ch02/textFile/Employee.java
@@ -0,0 +1,43 @@
+package textFile;
+
+import java.time.*;
+
+public class Employee
+{
+ private String name;
+ private double salary;
+ private LocalDate hireDay;
+
+ public Employee(String n, double s, int year, int month, int day)
+ {
+ name = n;
+ salary = s;
+ hireDay = LocalDate.of(year, month, day);
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public double getSalary()
+ {
+ return salary;
+ }
+
+ public LocalDate getHireDay()
+ {
+ return hireDay;
+ }
+
+ public void raiseSalary(double byPercent)
+ {
+ double raise = salary * byPercent / 100;
+ salary += raise;
+ }
+
+ public String toString()
+ {
+ return getClass().getName() + "[name=" + name + ",salary=" + salary + ",hireDay=" + hireDay + "]";
+ }
+}
diff --git a/corejava第10版/v2ch02/textFile/TextFileTest.java b/corejava第10版/v2ch02/textFile/TextFileTest.java
new file mode 100644
index 0000000..4290a08
--- /dev/null
+++ b/corejava第10版/v2ch02/textFile/TextFileTest.java
@@ -0,0 +1,97 @@
+package textFile;
+
+import java.io.*;
+import java.time.*;
+import java.util.*;
+
+/**
+ * @version 1.14 2016-07-11
+ * @author Cay Horstmann
+ */
+public class TextFileTest
+{
+ public static void main(String[] args) throws IOException
+ {
+ Employee[] staff = new Employee[3];
+
+ staff[0] = new Employee("Carl Cracker", 75000, 1987, 12, 15);
+ staff[1] = new Employee("Harry Hacker", 50000, 1989, 10, 1);
+ staff[2] = new Employee("Tony Tester", 40000, 1990, 3, 15);
+
+ // save all employee records to the file employee.dat
+ try (PrintWriter out = new PrintWriter("employee.dat", "UTF-8"))
+ {
+ writeData(staff, out);
+ }
+
+ // retrieve all records into a new array
+ try (Scanner in = new Scanner(
+ new FileInputStream("employee.dat"), "UTF-8"))
+ {
+ Employee[] newStaff = readData(in);
+
+ // print the newly read employee records
+ for (Employee e : newStaff)
+ System.out.println(e);
+ }
+ }
+
+ /**
+ * Writes all employees in an array to a print writer
+ * @param employees an array of employees
+ * @param out a print writer
+ */
+ private static void writeData(Employee[] employees, PrintWriter out) throws IOException
+ {
+ // write number of employees
+ out.println(employees.length);
+
+ for (Employee e : employees)
+ writeEmployee(out, e);
+ }
+
+ /**
+ * Reads an array of employees from a scanner
+ * @param in the scanner
+ * @return the array of employees
+ */
+ private static Employee[] readData(Scanner in)
+ {
+ // retrieve the array size
+ int n = in.nextInt();
+ in.nextLine(); // consume newline
+
+ Employee[] employees = new Employee[n];
+ for (int i = 0; i < n; i++)
+ {
+ employees[i] = readEmployee(in);
+ }
+ return employees;
+ }
+
+ /**
+ * Writes employee data to a print writer
+ * @param out the print writer
+ */
+ public static void writeEmployee(PrintWriter out, Employee e)
+ {
+ out.println(e.getName() + "|" + e.getSalary() + "|" + e.getHireDay());
+ }
+
+ /**
+ * Reads employee data from a buffered reader
+ * @param in the scanner
+ */
+ public static Employee readEmployee(Scanner in)
+ {
+ String line = in.nextLine();
+ String[] tokens = line.split("\\|");
+ String name = tokens[0];
+ double salary = Double.parseDouble(tokens[1]);
+ LocalDate hireDate = LocalDate.parse(tokens[2]);
+ int year = hireDate.getYear();
+ int month = hireDate.getMonthValue();
+ int day = hireDate.getDayOfMonth();
+ return new Employee(name, salary, year, month, day);
+ }
+}
diff --git a/javacore第11版/corejava/v2ch02/textFile/employee.dat b/corejava第10版/v2ch02/textFile/employee.dat
similarity index 100%
rename from javacore第11版/corejava/v2ch02/textFile/employee.dat
rename to corejava第10版/v2ch02/textFile/employee.dat
diff --git a/corejava第10版/v2ch02/zip/ZipTest.java b/corejava第10版/v2ch02/zip/ZipTest.java
new file mode 100644
index 0000000..3a98f37
--- /dev/null
+++ b/corejava第10版/v2ch02/zip/ZipTest.java
@@ -0,0 +1,58 @@
+package zip;
+
+import java.io.*;
+import java.nio.charset.*;
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.util.*;
+import java.util.zip.*;
+
+/**
+ * @version 1.41 2012-06-01
+ * @author Cay Horstmann
+ */
+public class ZipTest
+{
+ public static void main(String[] args) throws IOException
+ {
+ String zipname = args[0];
+ showContents(zipname);
+ System.out.println("---");
+ showContents2(zipname);
+ }
+
+ public static void showContents(String zipname) throws IOException
+ {
+ // Here, we use the classic zip API
+ try (ZipInputStream zin = new ZipInputStream(new FileInputStream(zipname)))
+ {
+ ZipEntry entry;
+ while ((entry = zin.getNextEntry()) != null)
+ {
+ System.out.println(entry.getName());
+
+ Scanner in = new Scanner(zin, "UTF-8");
+ while (in.hasNextLine())
+ System.out.println(" " + in.nextLine());
+ // DO NOT CLOSE in
+ zin.closeEntry();
+ }
+ }
+ }
+
+ public static void showContents2(String zipname) throws IOException
+ {
+ // Here, we make a Java SE 7 file system
+ FileSystem fs = FileSystems.newFileSystem(Paths.get(zipname), null);
+ Files.walkFileTree(fs.getPath("/"), new SimpleFileVisitor()
+ {
+ public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException
+ {
+ System.out.println(path);
+ for (String line : Files.readAllLines(path, Charset.forName("UTF-8")))
+ System.out.println(" " + line);
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch03/dom/TreeViewer.java b/corejava第10版/v2ch03/dom/TreeViewer.java
new file mode 100644
index 0000000..d385cc8
--- /dev/null
+++ b/corejava第10版/v2ch03/dom/TreeViewer.java
@@ -0,0 +1,229 @@
+package dom;
+
+import java.awt.*;
+import java.io.*;
+
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.table.*;
+import javax.swing.tree.*;
+import javax.xml.parsers.*;
+
+import org.w3c.dom.*;
+import org.w3c.dom.CharacterData;
+
+/**
+ * This program displays an XML document as a tree.
+ * @version 1.13 2016-04-27
+ * @author Cay Horstmann
+ */
+public class TreeViewer
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new DOMTreeFrame();
+ frame.setTitle("TreeViewer");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * This frame contains a tree that displays the contents of an XML document.
+ */
+class DOMTreeFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 400;
+ private static final int DEFAULT_HEIGHT = 400;
+
+ private DocumentBuilder builder;
+
+ public DOMTreeFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ JMenu fileMenu = new JMenu("File");
+ JMenuItem openItem = new JMenuItem("Open");
+ openItem.addActionListener(event -> openFile());
+ fileMenu.add(openItem);
+
+ JMenuItem exitItem = new JMenuItem("Exit");
+ exitItem.addActionListener(event -> System.exit(0));
+ fileMenu.add(exitItem);
+
+ JMenuBar menuBar = new JMenuBar();
+ menuBar.add(fileMenu);
+ setJMenuBar(menuBar);
+ }
+
+ /**
+ * Open a file and load the document.
+ */
+ public void openFile()
+ {
+ JFileChooser chooser = new JFileChooser();
+ chooser.setCurrentDirectory(new File("dom"));
+ chooser.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter("XML files", "xml"));
+ int r = chooser.showOpenDialog(this);
+ if (r != JFileChooser.APPROVE_OPTION) return;
+ final File file = chooser.getSelectedFile();
+
+ new SwingWorker()
+ {
+ protected Document doInBackground() throws Exception
+ {
+ if (builder == null)
+ {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ builder = factory.newDocumentBuilder();
+ }
+ return builder.parse(file);
+ }
+
+ protected void done()
+ {
+ try
+ {
+ Document doc = get();
+ JTree tree = new JTree(new DOMTreeModel(doc));
+ tree.setCellRenderer(new DOMTreeCellRenderer());
+
+ setContentPane(new JScrollPane(tree));
+ validate();
+ }
+ catch (Exception e)
+ {
+ JOptionPane.showMessageDialog(DOMTreeFrame.this, e);
+ }
+ }
+ }.execute();
+ }
+}
+
+/**
+ * This tree model describes the tree structure of an XML document.
+ */
+class DOMTreeModel implements TreeModel
+{
+ private Document doc;
+
+ /**
+ * Constructs a document tree model.
+ * @param doc the document
+ */
+ public DOMTreeModel(Document doc)
+ {
+ this.doc = doc;
+ }
+
+ public Object getRoot()
+ {
+ return doc.getDocumentElement();
+ }
+
+ public int getChildCount(Object parent)
+ {
+ Node node = (Node) parent;
+ NodeList list = node.getChildNodes();
+ return list.getLength();
+ }
+
+ public Object getChild(Object parent, int index)
+ {
+ Node node = (Node) parent;
+ NodeList list = node.getChildNodes();
+ return list.item(index);
+ }
+
+ public int getIndexOfChild(Object parent, Object child)
+ {
+ Node node = (Node) parent;
+ NodeList list = node.getChildNodes();
+ for (int i = 0; i < list.getLength(); i++)
+ if (getChild(node, i) == child) return i;
+ return -1;
+ }
+
+ public boolean isLeaf(Object node)
+ {
+ return getChildCount(node) == 0;
+ }
+
+ public void valueForPathChanged(TreePath path, Object newValue) {}
+ public void addTreeModelListener(TreeModelListener l) {}
+ public void removeTreeModelListener(TreeModelListener l) {}
+}
+
+/**
+ * This class renders an XML node.
+ */
+class DOMTreeCellRenderer extends DefaultTreeCellRenderer
+{
+ public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected,
+ boolean expanded, boolean leaf, int row, boolean hasFocus)
+ {
+ Node node = (Node) value;
+ if (node instanceof Element) return elementPanel((Element) node);
+
+ super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
+ if (node instanceof CharacterData) setText(characterString((CharacterData) node));
+ else setText(node.getClass() + ": " + node.toString());
+ return this;
+ }
+
+ public static JPanel elementPanel(Element e)
+ {
+ JPanel panel = new JPanel();
+ panel.add(new JLabel("Element: " + e.getTagName()));
+ final NamedNodeMap map = e.getAttributes();
+ panel.add(new JTable(new AbstractTableModel()
+ {
+ public int getRowCount()
+ {
+ return map.getLength();
+ }
+
+ public int getColumnCount()
+ {
+ return 2;
+ }
+
+ public Object getValueAt(int r, int c)
+ {
+ return c == 0 ? map.item(r).getNodeName() : map.item(r).getNodeValue();
+ }
+ }));
+ return panel;
+ }
+
+ private static String characterString(CharacterData node)
+ {
+ StringBuilder builder = new StringBuilder(node.getData());
+ for (int i = 0; i < builder.length(); i++)
+ {
+ if (builder.charAt(i) == '\r')
+ {
+ builder.replace(i, i + 1, "\\r");
+ i++;
+ }
+ else if (builder.charAt(i) == '\n')
+ {
+ builder.replace(i, i + 1, "\\n");
+ i++;
+ }
+ else if (builder.charAt(i) == '\t')
+ {
+ builder.replace(i, i + 1, "\\t");
+ i++;
+ }
+ }
+ if (node instanceof CDATASection) builder.insert(0, "CDATASection: ");
+ else if (node instanceof Text) builder.insert(0, "Text: ");
+ else if (node instanceof Comment) builder.insert(0, "Comment: ");
+
+ return builder.toString();
+ }
+}
diff --git a/javacore第11版/corejava/v2ch03/dom/server.xml b/corejava第10版/v2ch03/dom/server.xml
similarity index 100%
rename from javacore第11版/corejava/v2ch03/dom/server.xml
rename to corejava第10版/v2ch03/dom/server.xml
diff --git a/corejava第10版/v2ch03/fontdialog-schema.xml b/corejava第10版/v2ch03/fontdialog-schema.xml
new file mode 100644
index 0000000..21caba1
--- /dev/null
+++ b/corejava第10版/v2ch03/fontdialog-schema.xml
@@ -0,0 +1,85 @@
+
+
+
+
+
+ javax.swing.JLabel
+
+ text
+ Face:
+
+
+ |
+
+
+ javax.swing.JComboBox
+
+ |
+
+
+ javax.swing.JTextArea
+
+ text
+ The quick brown fox jumps over the lazy dog
+
+
+ editable
+ false
+
+
+ lineWrap
+ true
+
+
+ border
+
+
+ javax.swing.border.EtchedBorder
+
+
+
+
+ |
+
+
+
+
+ javax.swing.JLabel
+
+ text
+ Size:
+
+
+ |
+
+
+ javax.swing.JComboBox
+
+ |
+
+
+
+
+ javax.swing.JCheckBox
+
+ text
+ Bold
+
+
+ |
+
+
+
+
+ javax.swing.JCheckBox
+
+ text
+ Italic
+
+
+ |
+
+
+
+
diff --git a/corejava第10版/v2ch03/fontdialog.xml b/corejava第10版/v2ch03/fontdialog.xml
new file mode 100644
index 0000000..6940d55
--- /dev/null
+++ b/corejava第10版/v2ch03/fontdialog.xml
@@ -0,0 +1,93 @@
+
+
+
+
+
+
+ javax.swing.JLabel
+
+ text
+ Face:
+
+
+ |
+
+
+ javax.swing.JComboBox
+
+ |
+
+
+ javax.swing.JTextArea
+
+ text
+ The quick brown fox jumps over the lazy dog
+
+
+ editable
+ false
+
+
+ rows
+ 8
+
+
+ columns
+ 20
+
+
+ lineWrap
+ true
+
+
+ border
+
+
+ javax.swing.border.EtchedBorder
+
+
+
+
+ |
+
+
+
+
+ javax.swing.JLabel
+
+ text
+ Size:
+
+
+ |
+
+
+ javax.swing.JComboBox
+
+ |
+
+
+
+
+ javax.swing.JCheckBox
+
+ text
+ Bold
+
+
+ |
+
+
+
+
+ javax.swing.JCheckBox
+
+ text
+ Italic
+
+
+ |
+
+
+
+
diff --git a/corejava第10版/v2ch03/gridbag.dtd b/corejava第10版/v2ch03/gridbag.dtd
new file mode 100644
index 0000000..b6ee8f8
--- /dev/null
+++ b/corejava第10版/v2ch03/gridbag.dtd
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/corejava第10版/v2ch03/gridbag.xsd b/corejava第10版/v2ch03/gridbag.xsd
new file mode 100644
index 0000000..6c6fe9e
--- /dev/null
+++ b/corejava第10版/v2ch03/gridbag.xsd
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/corejava第10版/v2ch03/read/GridBagPane.java b/corejava第10版/v2ch03/read/GridBagPane.java
new file mode 100644
index 0000000..70a0cb3
--- /dev/null
+++ b/corejava第10版/v2ch03/read/GridBagPane.java
@@ -0,0 +1,202 @@
+package read;
+
+import java.awt.*;
+import java.beans.*;
+import java.io.*;
+import java.lang.reflect.*;
+import javax.swing.*;
+import javax.xml.parsers.*;
+import org.w3c.dom.*;
+
+/**
+ * This panel uses an XML file to describe its components and their grid bag layout positions.
+ */
+public class GridBagPane extends JPanel
+{
+ private GridBagConstraints constraints;
+
+ /**
+ * Constructs a grid bag pane.
+ * @param filename the name of the XML file that describes the pane's components and their
+ * positions
+ */
+ public GridBagPane(File file)
+ {
+ setLayout(new GridBagLayout());
+ constraints = new GridBagConstraints();
+
+ try
+ {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setValidating(true);
+
+ if (file.toString().contains("-schema"))
+ {
+ factory.setNamespaceAware(true);
+ final String JAXP_SCHEMA_LANGUAGE =
+ "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
+ final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
+ factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
+ }
+
+ factory.setIgnoringElementContentWhitespace(true);
+
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document doc = builder.parse(file);
+ parseGridbag(doc.getDocumentElement());
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Gets a component with a given name
+ * @param name a component name
+ * @return the component with the given name, or null if no component in this grid bag pane has
+ * the given name
+ */
+ public Component get(String name)
+ {
+ Component[] components = getComponents();
+ for (int i = 0; i < components.length; i++)
+ {
+ if (components[i].getName().equals(name)) return components[i];
+ }
+ return null;
+ }
+
+ /**
+ * Parses a gridbag element.
+ * @param e a gridbag element
+ */
+ private void parseGridbag(Element e)
+ {
+ NodeList rows = e.getChildNodes();
+ for (int i = 0; i < rows.getLength(); i++)
+ {
+ Element row = (Element) rows.item(i);
+ NodeList cells = row.getChildNodes();
+ for (int j = 0; j < cells.getLength(); j++)
+ {
+ Element cell = (Element) cells.item(j);
+ parseCell(cell, i, j);
+ }
+ }
+ }
+
+ /**
+ * Parses a cell element.
+ * @param e a cell element
+ * @param r the row of the cell
+ * @param c the column of the cell
+ */
+ private void parseCell(Element e, int r, int c)
+ {
+ // get attributes
+
+ String value = e.getAttribute("gridx");
+ if (value.length() == 0) // use default
+ {
+ if (c == 0) constraints.gridx = 0;
+ else constraints.gridx += constraints.gridwidth;
+ }
+ else constraints.gridx = Integer.parseInt(value);
+
+ value = e.getAttribute("gridy");
+ if (value.length() == 0) // use default
+ constraints.gridy = r;
+ else constraints.gridy = Integer.parseInt(value);
+
+ constraints.gridwidth = Integer.parseInt(e.getAttribute("gridwidth"));
+ constraints.gridheight = Integer.parseInt(e.getAttribute("gridheight"));
+ constraints.weightx = Integer.parseInt(e.getAttribute("weightx"));
+ constraints.weighty = Integer.parseInt(e.getAttribute("weighty"));
+ constraints.ipadx = Integer.parseInt(e.getAttribute("ipadx"));
+ constraints.ipady = Integer.parseInt(e.getAttribute("ipady"));
+
+ // use reflection to get integer values of static fields
+ Class cl = GridBagConstraints.class;
+
+ try
+ {
+ String name = e.getAttribute("fill");
+ Field f = cl.getField(name);
+ constraints.fill = f.getInt(cl);
+
+ name = e.getAttribute("anchor");
+ f = cl.getField(name);
+ constraints.anchor = f.getInt(cl);
+ }
+ catch (Exception ex) // the reflection methods can throw various exceptions
+ {
+ ex.printStackTrace();
+ }
+
+ Component comp = (Component) parseBean((Element) e.getFirstChild());
+ add(comp, constraints);
+ }
+
+ /**
+ * Parses a bean element.
+ * @param e a bean element
+ */
+ private Object parseBean(Element e)
+ {
+ try
+ {
+ NodeList children = e.getChildNodes();
+ Element classElement = (Element) children.item(0);
+ String className = ((Text) classElement.getFirstChild()).getData();
+
+ Class> cl = Class.forName(className);
+
+ Object obj = cl.newInstance();
+
+ if (obj instanceof Component) ((Component) obj).setName(e.getAttribute("id"));
+
+ for (int i = 1; i < children.getLength(); i++)
+ {
+ Node propertyElement = children.item(i);
+ Element nameElement = (Element) propertyElement.getFirstChild();
+ String propertyName = ((Text) nameElement.getFirstChild()).getData();
+
+ Element valueElement = (Element) propertyElement.getLastChild();
+ Object value = parseValue(valueElement);
+ BeanInfo beanInfo = Introspector.getBeanInfo(cl);
+ PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
+ boolean done = false;
+ for (int j = 0; !done && j < descriptors.length; j++)
+ {
+ if (descriptors[j].getName().equals(propertyName))
+ {
+ descriptors[j].getWriteMethod().invoke(obj, value);
+ done = true;
+ }
+ }
+ }
+ return obj;
+ }
+ catch (Exception ex) // the reflection methods can throw various exceptions
+ {
+ ex.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Parses a value element.
+ * @param e a value element
+ */
+ private Object parseValue(Element e)
+ {
+ Element child = (Element) e.getFirstChild();
+ if (child.getTagName().equals("bean")) return parseBean(child);
+ String text = ((Text) child.getFirstChild()).getData();
+ if (child.getTagName().equals("int")) return new Integer(text);
+ else if (child.getTagName().equals("boolean")) return new Boolean(text);
+ else if (child.getTagName().equals("string")) return text;
+ else return null;
+ }
+}
diff --git a/corejava第10版/v2ch03/read/GridBagTest.java b/corejava第10版/v2ch03/read/GridBagTest.java
new file mode 100644
index 0000000..2b6365e
--- /dev/null
+++ b/corejava第10版/v2ch03/read/GridBagTest.java
@@ -0,0 +1,84 @@
+package read;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import javax.swing.*;
+
+/**
+ * This program shows how to use an XML file to describe a gridbag layout
+ * @version 1.12 2016-04-27
+ * @author Cay Horstmann
+ */
+public class GridBagTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFileChooser chooser = new JFileChooser(".");
+ chooser.showOpenDialog(null);
+ File file = chooser.getSelectedFile();
+ JFrame frame = new FontFrame(file);
+ frame.setTitle("GridBagTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * This frame contains a font selection dialog that is described by an XML file.
+ * @param filename the file containing the user interface components for the dialog.
+ */
+class FontFrame extends JFrame
+{
+ private GridBagPane gridbag;
+ private JComboBox face;
+ private JComboBox size;
+ private JCheckBox bold;
+ private JCheckBox italic;
+
+ @SuppressWarnings("unchecked")
+ public FontFrame(File file)
+ {
+ gridbag = new GridBagPane(file);
+ add(gridbag);
+
+ face = (JComboBox) gridbag.get("face");
+ size = (JComboBox) gridbag.get("size");
+ bold = (JCheckBox) gridbag.get("bold");
+ italic = (JCheckBox) gridbag.get("italic");
+
+ face.setModel(new DefaultComboBoxModel(new String[] { "Serif",
+ "SansSerif", "Monospaced", "Dialog", "DialogInput" }));
+
+ size.setModel(new DefaultComboBoxModel(new String[] { "8",
+ "10", "12", "15", "18", "24", "36", "48" }));
+
+ ActionListener listener = event -> setSample();
+
+ face.addActionListener(listener);
+ size.addActionListener(listener);
+ bold.addActionListener(listener);
+ italic.addActionListener(listener);
+
+ setSample();
+ pack();
+ }
+
+ /**
+ * This method sets the text sample to the selected font.
+ */
+ public void setSample()
+ {
+ String fontFace = face.getItemAt(face.getSelectedIndex());
+ int fontSize = Integer.parseInt(size.getItemAt(size.getSelectedIndex()));
+ JTextArea sample = (JTextArea) gridbag.get("sample");
+ int fontStyle = (bold.isSelected() ? Font.BOLD : 0)
+ + (italic.isSelected() ? Font.ITALIC : 0);
+
+ sample.setFont(new Font(fontFace, fontStyle, fontSize));
+ sample.repaint();
+ }
+}
diff --git a/corejava第10版/v2ch03/sax/SAXTest.java b/corejava第10版/v2ch03/sax/SAXTest.java
new file mode 100644
index 0000000..204181e
--- /dev/null
+++ b/corejava第10版/v2ch03/sax/SAXTest.java
@@ -0,0 +1,51 @@
+package sax;
+
+import java.io.*;
+import java.net.*;
+import javax.xml.parsers.*;
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+
+/**
+ * This program demonstrates how to use a SAX parser. The program prints all hyperlinks of an
+ * XHTML web page.
+ * Usage: java sax.SAXTest URL
+ * @version 1.00 2001-09-29
+ * @author Cay Horstmann
+ */
+public class SAXTest
+{
+ public static void main(String[] args) throws Exception
+ {
+ String url;
+ if (args.length == 0)
+ {
+ url = "http://www.w3c.org";
+ System.out.println("Using " + url);
+ }
+ else url = args[0];
+
+ DefaultHandler handler = new DefaultHandler()
+ {
+ public void startElement(String namespaceURI, String lname, String qname,
+ Attributes attrs)
+ {
+ if (lname.equals("a") && attrs != null)
+ {
+ for (int i = 0; i < attrs.getLength(); i++)
+ {
+ String aname = attrs.getLocalName(i);
+ if (aname.equals("href")) System.out.println(attrs.getValue(i));
+ }
+ }
+ }
+ };
+
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+ SAXParser saxParser = factory.newSAXParser();
+ InputStream in = new URL(url).openStream();
+ saxParser.parse(in, handler);
+ }
+}
diff --git a/corejava第10版/v2ch03/stax/StAXTest.java b/corejava第10版/v2ch03/stax/StAXTest.java
new file mode 100644
index 0000000..cc76f56
--- /dev/null
+++ b/corejava第10版/v2ch03/stax/StAXTest.java
@@ -0,0 +1,43 @@
+package stax;
+
+import java.io.*;
+import java.net.*;
+import javax.xml.stream.*;
+
+/**
+ * This program demonstrates how to use a StAX parser. The program prints all hyperlinks links of an
+ * XHTML web page.
+ * Usage: java stax.StAXTest URL
+ * @author Cay Horstmann
+ * @version 1.0 2007-06-23
+ */
+public class StAXTest
+{
+ public static void main(String[] args) throws Exception
+ {
+ String urlString;
+ if (args.length == 0)
+ {
+ urlString = "http://www.w3c.org";
+ System.out.println("Using " + urlString);
+ }
+ else urlString = args[0];
+ URL url = new URL(urlString);
+ InputStream in = url.openStream();
+ XMLInputFactory factory = XMLInputFactory.newInstance();
+ XMLStreamReader parser = factory.createXMLStreamReader(in);
+ while (parser.hasNext())
+ {
+ int event = parser.next();
+ if (event == XMLStreamConstants.START_ELEMENT)
+ {
+ if (parser.getLocalName().equals("a"))
+ {
+ String href = parser.getAttributeValue(null, "href");
+ if (href != null)
+ System.out.println(href);
+ }
+ }
+ }
+ }
+}
diff --git a/corejava第10版/v2ch03/transform/TransformTest.java b/corejava第10版/v2ch03/transform/TransformTest.java
new file mode 100644
index 0000000..c1783e3
--- /dev/null
+++ b/corejava第10版/v2ch03/transform/TransformTest.java
@@ -0,0 +1,116 @@
+package transform;
+
+import java.io.*;
+import java.nio.file.*;
+import java.util.*;
+import javax.xml.transform.*;
+import javax.xml.transform.sax.*;
+import javax.xml.transform.stream.*;
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+
+/**
+ * This program demonstrates XSL transformations. It applies a transformation to a set of employee
+ * records. The records are stored in the file employee.dat and turned into XML format. Specify the
+ * stylesheet on the command line, e.g.
+ * java transform.TransformTest transform/makeprop.xsl
+ * @version 1.03 2016-04-27
+ * @author Cay Horstmann
+ */
+public class TransformTest
+{
+ public static void main(String[] args) throws Exception
+ {
+ Path path;
+ if (args.length > 0) path = Paths.get(args[0]);
+ else path = Paths.get("transform", "makehtml.xsl");
+ try (InputStream styleIn = Files.newInputStream(path))
+ {
+ StreamSource styleSource = new StreamSource(styleIn);
+
+ Transformer t = TransformerFactory.newInstance().newTransformer(styleSource);
+ t.setOutputProperty(OutputKeys.INDENT, "yes");
+ t.setOutputProperty(OutputKeys.METHOD, "xml");
+ t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
+
+ try (InputStream docIn = Files.newInputStream(Paths.get("transform", "employee.dat")))
+ {
+ t.transform(new SAXSource(new EmployeeReader(), new InputSource(docIn)),
+ new StreamResult(System.out));
+ }
+ }
+ }
+}
+
+/**
+ * This class reads the flat file employee.dat and reports SAX parser events to act as if it was
+ * parsing an XML file.
+ */
+class EmployeeReader implements XMLReader
+{
+ private ContentHandler handler;
+
+ public void parse(InputSource source) throws IOException, SAXException
+ {
+ InputStream stream = source.getByteStream();
+ BufferedReader in = new BufferedReader(new InputStreamReader(stream));
+ String rootElement = "staff";
+ AttributesImpl atts = new AttributesImpl();
+
+ if (handler == null) throw new SAXException("No content handler");
+
+ handler.startDocument();
+ handler.startElement("", rootElement, rootElement, atts);
+ String line;
+ while ((line = in.readLine()) != null)
+ {
+ handler.startElement("", "employee", "employee", atts);
+ StringTokenizer t = new StringTokenizer(line, "|");
+
+ handler.startElement("", "name", "name", atts);
+ String s = t.nextToken();
+ handler.characters(s.toCharArray(), 0, s.length());
+ handler.endElement("", "name", "name");
+
+ handler.startElement("", "salary", "salary", atts);
+ s = t.nextToken();
+ handler.characters(s.toCharArray(), 0, s.length());
+ handler.endElement("", "salary", "salary");
+
+ atts.addAttribute("", "year", "year", "CDATA", t.nextToken());
+ atts.addAttribute("", "month", "month", "CDATA", t.nextToken());
+ atts.addAttribute("", "day", "day", "CDATA", t.nextToken());
+ handler.startElement("", "hiredate", "hiredate", atts);
+ handler.endElement("", "hiredate", "hiredate");
+ atts.clear();
+
+ handler.endElement("", "employee", "employee");
+ }
+
+ handler.endElement("", rootElement, rootElement);
+ handler.endDocument();
+ }
+
+ public void setContentHandler(ContentHandler newValue)
+ {
+ handler = newValue;
+ }
+
+ public ContentHandler getContentHandler()
+ {
+ return handler;
+ }
+
+ // the following methods are just do-nothing implementations
+ public void parse(String systemId) throws IOException, SAXException {}
+ public void setErrorHandler(ErrorHandler handler) {}
+ public ErrorHandler getErrorHandler() { return null; }
+ public void setDTDHandler(DTDHandler handler) {}
+ public DTDHandler getDTDHandler() { return null; }
+ public void setEntityResolver(EntityResolver resolver) {}
+ public EntityResolver getEntityResolver() { return null; }
+ public void setProperty(String name, Object value) {}
+ public Object getProperty(String name) { return null; }
+ public void setFeature(String name, boolean value) {}
+ public boolean getFeature(String name) { return false; }
+}
diff --git a/javacore第11版/corejava/v2ch03/transform/employee.dat b/corejava第10版/v2ch03/transform/employee.dat
similarity index 100%
rename from javacore第11版/corejava/v2ch03/transform/employee.dat
rename to corejava第10版/v2ch03/transform/employee.dat
diff --git a/javacore第11版/corejava/v2ch03/transform/makehtml.xsl b/corejava第10版/v2ch03/transform/makehtml.xsl
similarity index 100%
rename from javacore第11版/corejava/v2ch03/transform/makehtml.xsl
rename to corejava第10版/v2ch03/transform/makehtml.xsl
diff --git a/javacore第11版/corejava/v2ch03/transform/makeprop.xsl b/corejava第10版/v2ch03/transform/makeprop.xsl
similarity index 100%
rename from javacore第11版/corejava/v2ch03/transform/makeprop.xsl
rename to corejava第10版/v2ch03/transform/makeprop.xsl
diff --git a/corejava第10版/v2ch03/write/RectangleComponent.java b/corejava第10版/v2ch03/write/RectangleComponent.java
new file mode 100644
index 0000000..49cdf89
--- /dev/null
+++ b/corejava第10版/v2ch03/write/RectangleComponent.java
@@ -0,0 +1,134 @@
+package write;
+
+import java.awt.*;
+import java.awt.geom.*;
+import java.util.*;
+import javax.swing.*;
+import javax.xml.parsers.*;
+import javax.xml.stream.*;
+import org.w3c.dom.*;
+
+/**
+ * A component that shows a set of colored rectangles
+ */
+public class RectangleComponent extends JComponent
+{
+ private static final Dimension PREFERRED_SIZE = new Dimension(300, 200);
+
+ private java.util.List rects;
+ private java.util.List colors;
+ private Random generator;
+ private DocumentBuilder builder;
+
+ public RectangleComponent()
+ {
+ rects = new ArrayList<>();
+ colors = new ArrayList<>();
+ generator = new Random();
+
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ try
+ {
+ builder = factory.newDocumentBuilder();
+ }
+ catch (ParserConfigurationException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Create a new random drawing.
+ */
+ public void newDrawing()
+ {
+ int n = 10 + generator.nextInt(20);
+ rects.clear();
+ colors.clear();
+ for (int i = 1; i <= n; i++)
+ {
+ int x = generator.nextInt(getWidth());
+ int y = generator.nextInt(getHeight());
+ int width = generator.nextInt(getWidth() - x);
+ int height = generator.nextInt(getHeight() - y);
+ rects.add(new Rectangle(x, y, width, height));
+ int r = generator.nextInt(256);
+ int g = generator.nextInt(256);
+ int b = generator.nextInt(256);
+ colors.add(new Color(r, g, b));
+ }
+ repaint();
+ }
+
+ public void paintComponent(Graphics g)
+ {
+ if (rects.size() == 0) newDrawing();
+ Graphics2D g2 = (Graphics2D) g;
+
+ // draw all rectangles
+ for (int i = 0; i < rects.size(); i++)
+ {
+ g2.setPaint(colors.get(i));
+ g2.fill(rects.get(i));
+ }
+ }
+
+ /**
+ * Creates an SVG document of the current drawing.
+ * @return the DOM tree of the SVG document
+ */
+ public Document buildDocument()
+ {
+ String namespace = "http://www.w3.org/2000/svg";
+ Document doc = builder.newDocument();
+ Element svgElement = doc.createElementNS(namespace, "svg");
+ doc.appendChild(svgElement);
+ svgElement.setAttribute("width", "" + getWidth());
+ svgElement.setAttribute("height", "" + getHeight());
+ for (int i = 0; i < rects.size(); i++)
+ {
+ Color c = colors.get(i);
+ Rectangle2D r = rects.get(i);
+ Element rectElement = doc.createElementNS(namespace, "rect");
+ rectElement.setAttribute("x", "" + r.getX());
+ rectElement.setAttribute("y", "" + r.getY());
+ rectElement.setAttribute("width", "" + r.getWidth());
+ rectElement.setAttribute("height", "" + r.getHeight());
+ rectElement.setAttribute("fill", String.format("#%06x",
+ c.getRGB() & 0xFFFFFF));
+ svgElement.appendChild(rectElement);
+ }
+ return doc;
+ }
+
+ /**
+ * Writes an SVG document of the current drawing.
+ * @param writer the document destination
+ */
+ public void writeDocument(XMLStreamWriter writer) throws XMLStreamException
+ {
+ writer.writeStartDocument();
+ writer.writeDTD("");
+ writer.writeStartElement("svg");
+ writer.writeDefaultNamespace("http://www.w3.org/2000/svg");
+ writer.writeAttribute("width", "" + getWidth());
+ writer.writeAttribute("height", "" + getHeight());
+ for (int i = 0; i < rects.size(); i++)
+ {
+ Color c = colors.get(i);
+ Rectangle2D r = rects.get(i);
+ writer.writeEmptyElement("rect");
+ writer.writeAttribute("x", "" + r.getX());
+ writer.writeAttribute("y", "" + r.getY());
+ writer.writeAttribute("width", "" + r.getWidth());
+ writer.writeAttribute("height", "" + r.getHeight());
+ writer.writeAttribute("fill", String.format("#%06x",
+ c.getRGB() & 0xFFFFFF));
+ }
+ writer.writeEndDocument(); // closes svg element
+ }
+
+ public Dimension getPreferredSize() { return PREFERRED_SIZE; }
+}
diff --git a/corejava第10版/v2ch03/write/XMLWriteFrame.java b/corejava第10版/v2ch03/write/XMLWriteFrame.java
new file mode 100644
index 0000000..01feefc
--- /dev/null
+++ b/corejava第10版/v2ch03/write/XMLWriteFrame.java
@@ -0,0 +1,107 @@
+package write;
+
+import java.io.*;
+import java.nio.file.*;
+
+import javax.swing.*;
+import javax.xml.stream.*;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.*;
+import javax.xml.transform.stream.*;
+
+import org.w3c.dom.*;
+
+/**
+ * A frame with a component for showing a modern drawing.
+ */
+public class XMLWriteFrame extends JFrame
+{
+ private RectangleComponent comp;
+ private JFileChooser chooser;
+
+ public XMLWriteFrame()
+ {
+ chooser = new JFileChooser();
+
+ // add component to frame
+
+ comp = new RectangleComponent();
+ add(comp);
+
+ // set up menu bar
+
+ JMenuBar menuBar = new JMenuBar();
+ setJMenuBar(menuBar);
+
+ JMenu menu = new JMenu("File");
+ menuBar.add(menu);
+
+ JMenuItem newItem = new JMenuItem("New");
+ menu.add(newItem);
+ newItem.addActionListener(event -> comp.newDrawing());
+
+ JMenuItem saveItem = new JMenuItem("Save with DOM/XSLT");
+ menu.add(saveItem);
+ saveItem.addActionListener(event -> saveDocument());
+
+ JMenuItem saveStAXItem = new JMenuItem("Save with StAX");
+ menu.add(saveStAXItem);
+ saveStAXItem.addActionListener(event -> saveStAX());
+
+ JMenuItem exitItem = new JMenuItem("Exit");
+ menu.add(exitItem);
+ exitItem.addActionListener(event -> System.exit(0));
+ pack();
+ }
+
+ /**
+ * Saves the drawing in SVG format, using DOM/XSLT
+ */
+ public void saveDocument()
+ {
+ try
+ {
+ if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION) return;
+ File file = chooser.getSelectedFile();
+ Document doc = comp.buildDocument();
+ Transformer t = TransformerFactory.newInstance().newTransformer();
+ t.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM,
+ "http://www.w3.org/TR/2000/CR-SVG-20000802/DTD/svg-20000802.dtd");
+ t.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "-//W3C//DTD SVG 20000802//EN");
+ t.setOutputProperty(OutputKeys.INDENT, "yes");
+ t.setOutputProperty(OutputKeys.METHOD, "xml");
+ t.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
+ t.transform(new DOMSource(doc), new StreamResult(Files.newOutputStream(file.toPath())));
+ }
+ catch (TransformerException | IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+
+ /**
+ * Saves the drawing in SVG format, using StAX
+ */
+ public void saveStAX()
+ {
+ if (chooser.showSaveDialog(this) != JFileChooser.APPROVE_OPTION) return;
+ File file = chooser.getSelectedFile();
+ XMLOutputFactory factory = XMLOutputFactory.newInstance();
+ try
+ {
+ XMLStreamWriter writer = factory.createXMLStreamWriter(Files.newOutputStream(file.toPath()));
+ try
+ {
+ comp.writeDocument(writer);
+ }
+ finally
+ {
+ writer.close(); // Not autocloseable
+ }
+ }
+ catch (XMLStreamException | IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch03/write/XMLWriteTest.java b/corejava第10版/v2ch03/write/XMLWriteTest.java
new file mode 100644
index 0000000..b1e0b18
--- /dev/null
+++ b/corejava第10版/v2ch03/write/XMLWriteTest.java
@@ -0,0 +1,24 @@
+package write;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program shows how to write an XML file. It saves a file describing a modern drawing in SVG
+ * format.
+ * @version 1.12 2016-04-27
+ * @author Cay Horstmann
+ */
+public class XMLWriteTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new XMLWriteFrame();
+ frame.setTitle("XMLWriteTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch03/xpath/XPathTester.java b/corejava第10版/v2ch03/xpath/XPathTester.java
new file mode 100644
index 0000000..935cc71
--- /dev/null
+++ b/corejava第10版/v2ch03/xpath/XPathTester.java
@@ -0,0 +1,155 @@
+package xpath;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.nio.file.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.border.*;
+import javax.xml.namespace.*;
+import javax.xml.parsers.*;
+import javax.xml.xpath.*;
+import org.w3c.dom.*;
+import org.xml.sax.*;
+
+/**
+ * This program evaluates XPath expressions.
+ * @version 1.02 2016-05-10
+ * @author Cay Horstmann
+ */
+public class XPathTester
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new XPathFrame();
+ frame.setTitle("XPathTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * This frame shows an XML document, a panel to type an XPath expression, and a text field to
+ * display the result.
+ */
+class XPathFrame extends JFrame
+{
+ private DocumentBuilder builder;
+ private Document doc;
+ private XPath path;
+ private JTextField expression;
+ private JTextField result;
+ private JTextArea docText;
+ private JComboBox typeCombo;
+
+ public XPathFrame()
+ {
+ JMenu fileMenu = new JMenu("File");
+ JMenuItem openItem = new JMenuItem("Open");
+ openItem.addActionListener(event -> openFile());
+ fileMenu.add(openItem);
+
+ JMenuItem exitItem = new JMenuItem("Exit");
+ exitItem.addActionListener(event -> System.exit(0));
+ fileMenu.add(exitItem);
+
+ JMenuBar menuBar = new JMenuBar();
+ menuBar.add(fileMenu);
+ setJMenuBar(menuBar);
+
+ ActionListener listener = event -> evaluate();
+ expression = new JTextField(20);
+ expression.addActionListener(listener);
+ JButton evaluateButton = new JButton("Evaluate");
+ evaluateButton.addActionListener(listener);
+
+ typeCombo = new JComboBox(new String[] {
+ "STRING", "NODE", "NODESET", "NUMBER", "BOOLEAN" });
+ typeCombo.setSelectedItem("STRING");
+
+ JPanel panel = new JPanel();
+ panel.add(expression);
+ panel.add(typeCombo);
+ panel.add(evaluateButton);
+ docText = new JTextArea(10, 40);
+ result = new JTextField();
+ result.setBorder(new TitledBorder("Result"));
+
+ add(panel, BorderLayout.NORTH);
+ add(new JScrollPane(docText), BorderLayout.CENTER);
+ add(result, BorderLayout.SOUTH);
+
+ try
+ {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ builder = factory.newDocumentBuilder();
+ }
+ catch (ParserConfigurationException e)
+ {
+ JOptionPane.showMessageDialog(this, e);
+ }
+
+ XPathFactory xpfactory = XPathFactory.newInstance();
+ path = xpfactory.newXPath();
+ pack();
+ }
+
+ /**
+ * Open a file and load the document.
+ */
+ public void openFile()
+ {
+ JFileChooser chooser = new JFileChooser();
+ chooser.setCurrentDirectory(new File("xpath"));
+
+ chooser.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter("XML files", "xml"));
+ int r = chooser.showOpenDialog(this);
+ if (r != JFileChooser.APPROVE_OPTION) return;
+ File file = chooser.getSelectedFile();
+ try
+ {
+ docText.setText(new String(Files.readAllBytes(file.toPath())));
+ doc = builder.parse(file);
+ }
+ catch (IOException e)
+ {
+ JOptionPane.showMessageDialog(this, e);
+ }
+ catch (SAXException e)
+ {
+ JOptionPane.showMessageDialog(this, e);
+ }
+ }
+
+ public void evaluate()
+ {
+ try
+ {
+ String typeName = (String) typeCombo.getSelectedItem();
+ QName returnType = (QName) XPathConstants.class.getField(typeName).get(null);
+ Object evalResult = path.evaluate(expression.getText(), doc, returnType);
+ if (typeName.equals("NODESET"))
+ {
+ NodeList list = (NodeList) evalResult;
+ // Can't use String.join since NodeList isn't Iterable
+ StringJoiner joiner = new StringJoiner(",", "{", "}");
+ for (int i = 0; i < list.getLength(); i++)
+ joiner.add("" + list.item(i));
+ result.setText("" + joiner);
+ }
+ else result.setText("" + evalResult);
+ }
+ catch (XPathExpressionException e)
+ {
+ result.setText("" + e);
+ }
+ catch (Exception e) // reflection exception
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/corejava第10版/v2ch03/xpath/fontdialog.xml b/corejava第10版/v2ch03/xpath/fontdialog.xml
new file mode 100644
index 0000000..59ef0fb
--- /dev/null
+++ b/corejava第10版/v2ch03/xpath/fontdialog.xml
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+ javax.swing.JLabel
+
+ text
+ Face:
+
+
+ |
+
+
+ javax.swing.JComboBox
+
+ |
+
+
+ javax.swing.JTextArea
+
+ text
+ The quick brown fox jumps over the lazy dog
+
+
+ editable
+ false
+
+
+ lineWrap
+ true
+
+
+ border
+
+
+ javax.swing.border.EtchedBorder
+
+
+
+
+ |
+
+
+
+
+ javax.swing.JLabel
+
+ text
+ Size:
+
+
+ |
+
+
+ javax.swing.JComboBox
+
+ |
+
+
+
+
+ javax.swing.JCheckBox
+
+ text
+ Bold
+
+
+ |
+
+
+
+
+ javax.swing.JCheckBox
+
+ text
+ Italic
+
+
+ |
+
+
+
+
diff --git a/corejava第10版/v2ch03/xpath/gridbag.dtd b/corejava第10版/v2ch03/xpath/gridbag.dtd
new file mode 100644
index 0000000..b6ee8f8
--- /dev/null
+++ b/corejava第10版/v2ch03/xpath/gridbag.dtd
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/corejava第10版/v2ch04/inetAddress/InetAddressTest.java b/corejava第10版/v2ch04/inetAddress/InetAddressTest.java
new file mode 100644
index 0000000..80874ca
--- /dev/null
+++ b/corejava第10版/v2ch04/inetAddress/InetAddressTest.java
@@ -0,0 +1,29 @@
+package inetAddress;
+
+import java.io.*;
+import java.net.*;
+
+/**
+ * This program demonstrates the InetAddress class. Supply a host name as command-line argument, or
+ * run without command-line arguments to see the address of the local host.
+ * @version 1.02 2012-06-05
+ * @author Cay Horstmann
+ */
+public class InetAddressTest
+{
+ public static void main(String[] args) throws IOException
+ {
+ if (args.length > 0)
+ {
+ String host = args[0];
+ InetAddress[] addresses = InetAddress.getAllByName(host);
+ for (InetAddress a : addresses)
+ System.out.println(a);
+ }
+ else
+ {
+ InetAddress localHostAddress = InetAddress.getLocalHost();
+ System.out.println(localHostAddress);
+ }
+ }
+}
diff --git a/corejava第10版/v2ch04/interruptible/InterruptibleSocketTest.java b/corejava第10版/v2ch04/interruptible/InterruptibleSocketTest.java
new file mode 100644
index 0000000..25918b3
--- /dev/null
+++ b/corejava第10版/v2ch04/interruptible/InterruptibleSocketTest.java
@@ -0,0 +1,240 @@
+package interruptible;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.net.*;
+import java.io.*;
+import java.nio.channels.*;
+import javax.swing.*;
+
+/**
+ * This program shows how to interrupt a socket channel.
+ * @author Cay Horstmann
+ * @version 1.04 2016-04-27
+ */
+public class InterruptibleSocketTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new InterruptibleSocketFrame();
+ frame.setTitle("InterruptibleSocketTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+class InterruptibleSocketFrame extends JFrame
+{
+ private Scanner in;
+ private JButton interruptibleButton;
+ private JButton blockingButton;
+ private JButton cancelButton;
+ private JTextArea messages;
+ private TestServer server;
+ private Thread connectThread;
+
+ public InterruptibleSocketFrame()
+ {
+ JPanel northPanel = new JPanel();
+ add(northPanel, BorderLayout.NORTH);
+
+ final int TEXT_ROWS = 20;
+ final int TEXT_COLUMNS = 60;
+ messages = new JTextArea(TEXT_ROWS, TEXT_COLUMNS);
+ add(new JScrollPane(messages));
+
+ interruptibleButton = new JButton("Interruptible");
+ blockingButton = new JButton("Blocking");
+
+ northPanel.add(interruptibleButton);
+ northPanel.add(blockingButton);
+
+ interruptibleButton.addActionListener(event ->
+ {
+ interruptibleButton.setEnabled(false);
+ blockingButton.setEnabled(false);
+ cancelButton.setEnabled(true);
+ connectThread = new Thread(() ->
+ {
+ try
+ {
+ connectInterruptibly();
+ }
+ catch (IOException e)
+ {
+ messages.append("\nInterruptibleSocketTest.connectInterruptibly: " + e);
+ }
+ });
+ connectThread.start();
+ });
+
+ blockingButton.addActionListener(event ->
+ {
+ interruptibleButton.setEnabled(false);
+ blockingButton.setEnabled(false);
+ cancelButton.setEnabled(true);
+ connectThread = new Thread(() ->
+ {
+ try
+ {
+ connectBlocking();
+ }
+ catch (IOException e)
+ {
+ messages.append("\nInterruptibleSocketTest.connectBlocking: " + e);
+ }
+ });
+ connectThread.start();
+ });
+
+ cancelButton = new JButton("Cancel");
+ cancelButton.setEnabled(false);
+ northPanel.add(cancelButton);
+ cancelButton.addActionListener(event ->
+ {
+ connectThread.interrupt();
+ cancelButton.setEnabled(false);
+ });
+ server = new TestServer();
+ new Thread(server).start();
+ pack();
+ }
+
+ /**
+ * Connects to the test server, using interruptible I/O
+ */
+ public void connectInterruptibly() throws IOException
+ {
+ messages.append("Interruptible:\n");
+ try (SocketChannel channel = SocketChannel.open(new InetSocketAddress("localhost", 8189)))
+ {
+ in = new Scanner(channel, "UTF-8");
+ while (!Thread.currentThread().isInterrupted())
+ {
+ messages.append("Reading ");
+ if (in.hasNextLine())
+ {
+ String line = in.nextLine();
+ messages.append(line);
+ messages.append("\n");
+ }
+ }
+ }
+ finally
+ {
+ EventQueue.invokeLater(() ->
+ {
+ messages.append("Channel closed\n");
+ interruptibleButton.setEnabled(true);
+ blockingButton.setEnabled(true);
+ });
+ }
+ }
+
+ /**
+ * Connects to the test server, using blocking I/O
+ */
+ public void connectBlocking() throws IOException
+ {
+ messages.append("Blocking:\n");
+ try (Socket sock = new Socket("localhost", 8189))
+ {
+ in = new Scanner(sock.getInputStream(), "UTF-8");
+ while (!Thread.currentThread().isInterrupted())
+ {
+ messages.append("Reading ");
+ if (in.hasNextLine())
+ {
+ String line = in.nextLine();
+ messages.append(line);
+ messages.append("\n");
+ }
+ }
+ }
+ finally
+ {
+ EventQueue.invokeLater(() ->
+ {
+ messages.append("Socket closed\n");
+ interruptibleButton.setEnabled(true);
+ blockingButton.setEnabled(true);
+ });
+ }
+ }
+
+ /**
+ * A multithreaded server that listens to port 8189 and sends numbers to the client, simulating
+ * a hanging server after 10 numbers.
+ */
+ class TestServer implements Runnable
+ {
+ public void run()
+ {
+ try (ServerSocket s = new ServerSocket(8189))
+ {
+ while (true)
+ {
+ Socket incoming = s.accept();
+ Runnable r = new TestServerHandler(incoming);
+ Thread t = new Thread(r);
+ t.start();
+ }
+ }
+ catch (IOException e)
+ {
+ messages.append("\nTestServer.run: " + e);
+ }
+ }
+ }
+
+ /**
+ * This class handles the client input for one server socket connection.
+ */
+ class TestServerHandler implements Runnable
+ {
+ private Socket incoming;
+ private int counter;
+
+ /**
+ * Constructs a handler.
+ * @param i the incoming socket
+ */
+ public TestServerHandler(Socket i)
+ {
+ incoming = i;
+ }
+
+ public void run()
+ {
+ try
+ {
+ try
+ {
+ OutputStream outStream = incoming.getOutputStream();
+ PrintWriter out = new PrintWriter(
+ new OutputStreamWriter(outStream, "UTF-8"),
+ true /* autoFlush */);
+ while (counter < 100)
+ {
+ counter++;
+ if (counter <= 10) out.println(counter);
+ Thread.sleep(100);
+ }
+ }
+ finally
+ {
+ incoming.close();
+ messages.append("Closing server\n");
+ }
+ }
+ catch (Exception e)
+ {
+ messages.append("\nTestServerHandler.run: " + e);
+ }
+ }
+ }
+}
diff --git a/corejava第10版/v2ch04/mail/MailTest.java b/corejava第10版/v2ch04/mail/MailTest.java
new file mode 100644
index 0000000..effd7a7
--- /dev/null
+++ b/corejava第10版/v2ch04/mail/MailTest.java
@@ -0,0 +1,59 @@
+package mail;
+
+import java.io.*;
+import java.nio.charset.*;
+import java.nio.file.*;
+import java.util.*;
+import javax.mail.*;
+import javax.mail.internet.*;
+import javax.mail.internet.MimeMessage.RecipientType;
+
+/**
+ * This program shows how to use JavaMail to send mail messages.
+ * @author Cay Horstmann
+ * @version 1.00 2012-06-04
+ */
+public class MailTest
+{
+ public static void main(String[] args) throws MessagingException, IOException
+ {
+ Properties props = new Properties();
+ try (InputStream in = Files.newInputStream(Paths.get("mail", "mail.properties")))
+ {
+ props.load(in);
+ }
+ List lines = Files.readAllLines(Paths.get(args[0]), Charset.forName("UTF-8"));
+
+ String from = lines.get(0);
+ String to = lines.get(1);
+ String subject = lines.get(2);
+
+ StringBuilder builder = new StringBuilder();
+ for (int i = 3; i < lines.size(); i++)
+ {
+ builder.append(lines.get(i));
+ builder.append("\n");
+ }
+
+ Console console = System.console();
+ String password = new String(console.readPassword("Password: "));
+
+ Session mailSession = Session.getDefaultInstance(props);
+ // mailSession.setDebug(true);
+ MimeMessage message = new MimeMessage(mailSession);
+ message.setFrom(new InternetAddress(from));
+ message.addRecipient(RecipientType.TO, new InternetAddress(to));
+ message.setSubject(subject);
+ message.setText(builder.toString());
+ Transport tr = mailSession.getTransport();
+ try
+ {
+ tr.connect(null, password);
+ tr.sendMessage(message, message.getAllRecipients());
+ }
+ finally
+ {
+ tr.close();
+ }
+ }
+}
diff --git a/corejava第10版/v2ch04/mail/mail.properties b/corejava第10版/v2ch04/mail/mail.properties
new file mode 100644
index 0000000..e6c34c3
--- /dev/null
+++ b/corejava第10版/v2ch04/mail/mail.properties
@@ -0,0 +1,4 @@
+mail.transport.protocol=smtps
+mail.smtps.auth=true
+mail.smtps.host=smtp.gmail.com
+mail.smtps.user=cayhorstmann@gmail.com
diff --git a/corejava第10版/v2ch04/mail/message.txt b/corejava第10版/v2ch04/mail/message.txt
new file mode 100644
index 0000000..7653787
--- /dev/null
+++ b/corejava第10版/v2ch04/mail/message.txt
@@ -0,0 +1,12 @@
+president@whitehouse.gov
+you@yourcompany.com
+Invitation
+Dear You:
+
+It is my pleasure to invite you to a black-tie reception
+on the front lawn of the White House on April 1, 2013.
+
+Sincerely,
+
+
+Barack Obama
diff --git a/corejava第10版/v2ch04/post/PostTest.java b/corejava第10版/v2ch04/post/PostTest.java
new file mode 100644
index 0000000..b1e5fe7
--- /dev/null
+++ b/corejava第10版/v2ch04/post/PostTest.java
@@ -0,0 +1,114 @@
+package post;
+
+import java.io.*;
+import java.net.*;
+import java.nio.file.*;
+import java.util.*;
+
+/**
+ * This program demonstrates how to use the URLConnection class for a POST request.
+ * @version 1.40 2016-04-24
+ * @author Cay Horstmann
+ */
+public class PostTest
+{
+ public static void main(String[] args) throws IOException
+ {
+ String propsFilename = args.length > 0 ? args[0] : "post/post.properties";
+ Properties props = new Properties();
+ try (InputStream in = Files.newInputStream(Paths.get(propsFilename)))
+ {
+ props.load(in);
+ }
+ String urlString = props.remove("url").toString();
+ Object userAgent = props.remove("User-Agent");
+ Object redirects = props.remove("redirects");
+ CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
+ String result = doPost(new URL(urlString), props,
+ userAgent == null ? null : userAgent.toString(),
+ redirects == null ? -1 : Integer.parseInt(redirects.toString()));
+ System.out.println(result);
+ }
+
+ /**
+ * Do an HTTP POST.
+ * @param url the URL to post to
+ * @param nameValuePairs the query parameters
+ * @param userAgent the user agent to use, or null for the default user agent
+ * @param redirects the number of redirects to follow manually, or -1 for automatic redirects
+ * @return the data returned from the server
+ */
+ public static String doPost(URL url, Map nameValuePairs, String userAgent, int redirects)
+ throws IOException
+ {
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ if (userAgent != null)
+ connection.setRequestProperty("User-Agent", userAgent);
+
+ if (redirects >= 0)
+ connection.setInstanceFollowRedirects(false);
+
+ connection.setDoOutput(true);
+
+ try (PrintWriter out = new PrintWriter(connection.getOutputStream()))
+ {
+ boolean first = true;
+ for (Map.Entry pair : nameValuePairs.entrySet())
+ {
+ if (first) first = false;
+ else out.print('&');
+ String name = pair.getKey().toString();
+ String value = pair.getValue().toString();
+ out.print(name);
+ out.print('=');
+ out.print(URLEncoder.encode(value, "UTF-8"));
+ }
+ }
+ String encoding = connection.getContentEncoding();
+ if (encoding == null) encoding = "UTF-8";
+
+ if (redirects > 0)
+ {
+ int responseCode = connection.getResponseCode();
+ if (responseCode == HttpURLConnection.HTTP_MOVED_PERM
+ || responseCode == HttpURLConnection.HTTP_MOVED_TEMP
+ || responseCode == HttpURLConnection.HTTP_SEE_OTHER)
+ {
+ String location = connection.getHeaderField("Location");
+ if (location != null)
+ {
+ URL base = connection.getURL();
+ connection.disconnect();
+ return doPost(new URL(base, location), nameValuePairs, userAgent, redirects - 1);
+ }
+
+ }
+ }
+ else if (redirects == 0)
+ {
+ throw new IOException("Too many redirects");
+ }
+
+ StringBuilder response = new StringBuilder();
+ try (Scanner in = new Scanner(connection.getInputStream(), encoding))
+ {
+ while (in.hasNextLine())
+ {
+ response.append(in.nextLine());
+ response.append("\n");
+ }
+ }
+ catch (IOException e)
+ {
+ InputStream err = connection.getErrorStream();
+ if (err == null) throw e;
+ try (Scanner in = new Scanner(err))
+ {
+ response.append(in.nextLine());
+ response.append("\n");
+ }
+ }
+
+ return response.toString();
+ }
+}
diff --git a/corejava第10版/v2ch04/post/post.properties b/corejava第10版/v2ch04/post/post.properties
new file mode 100644
index 0000000..bbd6b76
--- /dev/null
+++ b/corejava第10版/v2ch04/post/post.properties
@@ -0,0 +1,12 @@
+# https://www.ssa.gov/locator
+# url=https://secure.ssa.gov/ICON/ic001.do
+# zipCodeSearched=94118
+url=https://tools.usps.com/go/ZipLookupAction.action
+User-Agent=HTTPie/0.9.2
+redirects=10
+tCompany=
+tAddress=1 Market Street
+tApt=
+tCity=San Francisco
+sState=CA
+mode=1
\ No newline at end of file
diff --git a/corejava第10版/v2ch04/server/EchoServer.java b/corejava第10版/v2ch04/server/EchoServer.java
new file mode 100644
index 0000000..6852cae
--- /dev/null
+++ b/corejava第10版/v2ch04/server/EchoServer.java
@@ -0,0 +1,46 @@
+package server;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+/**
+ * This program implements a simple server that listens to port 8189 and echoes back all client
+ * input.
+ * @version 1.21 2012-05-19
+ * @author Cay Horstmann
+ */
+public class EchoServer
+{
+ public static void main(String[] args) throws IOException
+ {
+ // establish server socket
+ try (ServerSocket s = new ServerSocket(8189))
+ {
+ // wait for client connection
+ try (Socket incoming = s.accept())
+ {
+ InputStream inStream = incoming.getInputStream();
+ OutputStream outStream = incoming.getOutputStream();
+
+ try (Scanner in = new Scanner(inStream, "UTF-8"))
+ {
+ PrintWriter out = new PrintWriter(
+ new OutputStreamWriter(outStream, "UTF-8"),
+ true /* autoFlush */);
+
+ out.println("Hello! Enter BYE to exit.");
+
+ // echo client input
+ boolean done = false;
+ while (!done && in.hasNextLine())
+ {
+ String line = in.nextLine();
+ out.println("Echo: " + line);
+ if (line.trim().equals("BYE")) done = true;
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch04/socket/SocketTest.java b/corejava第10版/v2ch04/socket/SocketTest.java
new file mode 100644
index 0000000..5c33e81
--- /dev/null
+++ b/corejava第10版/v2ch04/socket/SocketTest.java
@@ -0,0 +1,28 @@
+package socket;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+/**
+ * This program makes a socket connection to the atomic clock in Boulder, Colorado, and prints
+ * the time that the server sends.
+ *
+ * @version 1.21 2016-04-27
+ * @author Cay Horstmann
+ */
+public class SocketTest
+{
+ public static void main(String[] args) throws IOException
+ {
+ try (Socket s = new Socket("time-a.nist.gov", 13);
+ Scanner in = new Scanner(s.getInputStream(), "UTF-8"))
+ {
+ while (in.hasNextLine())
+ {
+ String line = in.nextLine();
+ System.out.println(line);
+ }
+ }
+ }
+}
diff --git a/corejava第10版/v2ch04/threaded/ThreadedEchoServer.java b/corejava第10版/v2ch04/threaded/ThreadedEchoServer.java
new file mode 100644
index 0000000..33fde7a
--- /dev/null
+++ b/corejava第10版/v2ch04/threaded/ThreadedEchoServer.java
@@ -0,0 +1,81 @@
+package threaded;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+/**
+ * This program implements a multithreaded server that listens to port 8189 and echoes back
+ * all client input.
+ * @author Cay Horstmann
+ * @version 1.22 2016-04-27
+ */
+public class ThreadedEchoServer
+{
+ public static void main(String[] args )
+ {
+ try (ServerSocket s = new ServerSocket(8189))
+ {
+ int i = 1;
+
+ while (true)
+ {
+ Socket incoming = s.accept();
+ System.out.println("Spawning " + i);
+ Runnable r = new ThreadedEchoHandler(incoming);
+ Thread t = new Thread(r);
+ t.start();
+ i++;
+ }
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
+
+/**
+ * This class handles the client input for one server socket connection.
+ */
+class ThreadedEchoHandler implements Runnable
+{
+ private Socket incoming;
+
+ /**
+ Constructs a handler.
+ @param incomingSocket the incoming socket
+ */
+ public ThreadedEchoHandler(Socket incomingSocket)
+ {
+ incoming = incomingSocket;
+ }
+
+ public void run()
+ {
+ try (InputStream inStream = incoming.getInputStream();
+ OutputStream outStream = incoming.getOutputStream())
+ {
+ Scanner in = new Scanner(inStream, "UTF-8");
+ PrintWriter out = new PrintWriter(
+ new OutputStreamWriter(outStream, "UTF-8"),
+ true /* autoFlush */);
+
+ out.println( "Hello! Enter BYE to exit." );
+
+ // echo client input
+ boolean done = false;
+ while (!done && in.hasNextLine())
+ {
+ String line = in.nextLine();
+ out.println("Echo: " + line);
+ if (line.trim().equals("BYE"))
+ done = true;
+ }
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/corejava第10版/v2ch04/urlConnection/URLConnectionTest.java b/corejava第10版/v2ch04/urlConnection/URLConnectionTest.java
new file mode 100644
index 0000000..d4cf5d9
--- /dev/null
+++ b/corejava第10版/v2ch04/urlConnection/URLConnectionTest.java
@@ -0,0 +1,81 @@
+package urlConnection;
+
+import java.io.*;
+import java.net.*;
+import java.nio.charset.*;
+import java.util.*;
+
+/**
+ * This program connects to an URL and displays the response header data and the first 10 lines of
+ * the requested data.
+ *
+ * Supply the URL and an optional username and password (for HTTP basic authentication) on the
+ * command line.
+ * @version 1.11 2007-06-26
+ * @author Cay Horstmann
+ */
+public class URLConnectionTest
+{
+ public static void main(String[] args)
+ {
+ try
+ {
+ String urlName;
+ if (args.length > 0) urlName = args[0];
+ else urlName = "http://horstmann.com";
+
+ URL url = new URL(urlName);
+ URLConnection connection = url.openConnection();
+
+ // set username, password if specified on command line
+
+ if (args.length > 2)
+ {
+ String username = args[1];
+ String password = args[2];
+ String input = username + ":" + password;
+ Base64.Encoder encoder = Base64.getEncoder();
+ String encoding = encoder.encodeToString(input.getBytes(StandardCharsets.UTF_8));
+ connection.setRequestProperty("Authorization", "Basic " + encoding);
+ }
+
+ connection.connect();
+
+ // print header fields
+
+ Map> headers = connection.getHeaderFields();
+ for (Map.Entry> entry : headers.entrySet())
+ {
+ String key = entry.getKey();
+ for (String value : entry.getValue())
+ System.out.println(key + ": " + value);
+ }
+
+ // print convenience functions
+
+ System.out.println("----------");
+ System.out.println("getContentType: " + connection.getContentType());
+ System.out.println("getContentLength: " + connection.getContentLength());
+ System.out.println("getContentEncoding: " + connection.getContentEncoding());
+ System.out.println("getDate: " + connection.getDate());
+ System.out.println("getExpiration: " + connection.getExpiration());
+ System.out.println("getLastModifed: " + connection.getLastModified());
+ System.out.println("----------");
+
+ String encoding = connection.getContentEncoding();
+ if (encoding == null) encoding = "UTF-8";
+ try (Scanner in = new Scanner(connection.getInputStream(), encoding))
+ {
+ // print first ten lines of contents
+
+ for (int n = 1; in.hasNextLine() && n <= 10; n++)
+ System.out.println(in.nextLine());
+ if (in.hasNextLine()) System.out.println(". . .");
+ }
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/javacore第11版/corejava/v2ch05/Authors.sql b/corejava第10版/v2ch05/Authors.sql
similarity index 100%
rename from javacore第11版/corejava/v2ch05/Authors.sql
rename to corejava第10版/v2ch05/Authors.sql
diff --git a/javacore第11版/corejava/v2ch05/Books.sql b/corejava第10版/v2ch05/Books.sql
similarity index 100%
rename from javacore第11版/corejava/v2ch05/Books.sql
rename to corejava第10版/v2ch05/Books.sql
diff --git a/javacore第11版/corejava/v2ch05/BooksAuthors.sql b/corejava第10版/v2ch05/BooksAuthors.sql
similarity index 100%
rename from javacore第11版/corejava/v2ch05/BooksAuthors.sql
rename to corejava第10版/v2ch05/BooksAuthors.sql
diff --git a/javacore第11版/corejava/v2ch05/Publishers.sql b/corejava第10版/v2ch05/Publishers.sql
similarity index 100%
rename from javacore第11版/corejava/v2ch05/Publishers.sql
rename to corejava第10版/v2ch05/Publishers.sql
diff --git a/javacore第11版/corejava/v2ch05/database.properties b/corejava第10版/v2ch05/database.properties
similarity index 100%
rename from javacore第11版/corejava/v2ch05/database.properties
rename to corejava第10版/v2ch05/database.properties
diff --git a/javacore第11版/corejava/v2ch05/derby.log b/corejava第10版/v2ch05/derby.log
similarity index 100%
rename from javacore第11版/corejava/v2ch05/derby.log
rename to corejava第10版/v2ch05/derby.log
diff --git a/corejava第10版/v2ch05/exec/ExecSQL.java b/corejava第10版/v2ch05/exec/ExecSQL.java
new file mode 100644
index 0000000..8c16e9b
--- /dev/null
+++ b/corejava第10版/v2ch05/exec/ExecSQL.java
@@ -0,0 +1,116 @@
+package exec;
+
+import java.io.*;
+import java.nio.file.*;
+import java.util.*;
+import java.sql.*;
+
+/**
+ * Executes all SQL statements in a file. Call this program as
+ * java -classpath driverPath:. ExecSQL commandFile
+ *
+ * @version 1.32 2016-04-27
+ * @author Cay Horstmann
+ */
+class ExecSQL
+{
+ public static void main(String args[]) throws IOException
+ {
+ try (Scanner in = args.length == 0 ? new Scanner(System.in)
+ : new Scanner(Paths.get(args[0]), "UTF-8"))
+ {
+ try (Connection conn = getConnection();
+ Statement stat = conn.createStatement())
+ {
+ while (true)
+ {
+ if (args.length == 0) System.out.println("Enter command or EXIT to exit:");
+
+ if (!in.hasNextLine()) return;
+
+ String line = in.nextLine().trim();
+ if (line.equalsIgnoreCase("EXIT")) return;
+ if (line.endsWith(";")) // remove trailing semicolon
+ {
+ line = line.substring(0, line.length() - 1);
+ }
+ try
+ {
+ boolean isResult = stat.execute(line);
+ if (isResult)
+ {
+ try (ResultSet rs = stat.getResultSet())
+ {
+ showResultSet(rs);
+ }
+ }
+ else
+ {
+ int updateCount = stat.getUpdateCount();
+ System.out.println(updateCount + " rows updated");
+ }
+ }
+ catch (SQLException ex)
+ {
+ for (Throwable e : ex)
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ catch (SQLException e)
+ {
+ for (Throwable t : e)
+ t.printStackTrace();
+ }
+ }
+
+ /**
+ * Gets a connection from the properties specified in the file database.properties
+ * @return the database connection
+ */
+ public static Connection getConnection() throws SQLException, IOException
+ {
+ Properties props = new Properties();
+ try (InputStream in = Files.newInputStream(Paths.get("database.properties")))
+ {
+ props.load(in);
+ }
+
+ String drivers = props.getProperty("jdbc.drivers");
+ if (drivers != null) System.setProperty("jdbc.drivers", drivers);
+
+ String url = props.getProperty("jdbc.url");
+ String username = props.getProperty("jdbc.username");
+ String password = props.getProperty("jdbc.password");
+
+ return DriverManager.getConnection(url, username, password);
+ }
+
+ /**
+ * Prints a result set.
+ * @param result the result set to be printed
+ */
+ public static void showResultSet(ResultSet result) throws SQLException
+ {
+ ResultSetMetaData metaData = result.getMetaData();
+ int columnCount = metaData.getColumnCount();
+
+ for (int i = 1; i <= columnCount; i++)
+ {
+ if (i > 1) System.out.print(", ");
+ System.out.print(metaData.getColumnLabel(i));
+ }
+ System.out.println();
+
+ while (result.next())
+ {
+ for (int i = 1; i <= columnCount; i++)
+ {
+ if (i > 1) System.out.print(", ");
+ System.out.print(result.getString(i));
+ }
+ System.out.println();
+ }
+ }
+}
diff --git a/corejava第10版/v2ch05/query/QueryTest.java b/corejava第10版/v2ch05/query/QueryTest.java
new file mode 100644
index 0000000..14fa293
--- /dev/null
+++ b/corejava第10版/v2ch05/query/QueryTest.java
@@ -0,0 +1,175 @@
+package query;
+
+import java.io.*;
+import java.nio.file.*;
+import java.sql.*;
+import java.util.*;
+
+/**
+ * This program demonstrates several complex database queries.
+ * @version 1.30 2012-06-05
+ * @author Cay Horstmann
+ */
+public class QueryTest
+{
+ private static final String allQuery = "SELECT Books.Price, Books.Title FROM Books";
+
+ private static final String authorPublisherQuery = "SELECT Books.Price, Books.Title"
+ + " FROM Books, BooksAuthors, Authors, Publishers"
+ + " WHERE Authors.Author_Id = BooksAuthors.Author_Id AND BooksAuthors.ISBN = Books.ISBN"
+ + " AND Books.Publisher_Id = Publishers.Publisher_Id AND Authors.Name = ?"
+ + " AND Publishers.Name = ?";
+
+ private static final String authorQuery
+ = "SELECT Books.Price, Books.Title FROM Books, BooksAuthors, Authors"
+ + " WHERE Authors.Author_Id = BooksAuthors.Author_Id AND BooksAuthors.ISBN = Books.ISBN"
+ + " AND Authors.Name = ?";
+
+ private static final String publisherQuery
+ = "SELECT Books.Price, Books.Title FROM Books, Publishers"
+ + " WHERE Books.Publisher_Id = Publishers.Publisher_Id AND Publishers.Name = ?";
+
+
+ private static final String priceUpdate = "UPDATE Books " + "SET Price = Price + ? "
+ + " WHERE Books.Publisher_Id = (SELECT Publisher_Id FROM Publishers WHERE Name = ?)";
+
+ private static Scanner in;
+ private static ArrayList authors = new ArrayList<>();
+ private static ArrayList publishers = new ArrayList<>();
+
+ public static void main(String[] args) throws IOException
+ {
+ try (Connection conn = getConnection())
+ {
+ in = new Scanner(System.in);
+ authors.add("Any");
+ publishers.add("Any");
+ try (Statement stat = conn.createStatement())
+ {
+ // Fill the authors array list
+ String query = "SELECT Name FROM Authors";
+ try (ResultSet rs = stat.executeQuery(query))
+ {
+ while (rs.next())
+ authors.add(rs.getString(1));
+ }
+
+ // Fill the publishers array list
+ query = "SELECT Name FROM Publishers";
+ try (ResultSet rs = stat.executeQuery(query))
+ {
+ while (rs.next())
+ publishers.add(rs.getString(1));
+ }
+ }
+ boolean done = false;
+ while (!done)
+ {
+ System.out.print("Q)uery C)hange prices E)xit: ");
+ String input = in.next().toUpperCase();
+ if (input.equals("Q"))
+ executeQuery(conn);
+ else if (input.equals("C"))
+ changePrices(conn);
+ else
+ done = true;
+ }
+ }
+ catch (SQLException e)
+ {
+ for (Throwable t : e)
+ System.out.println(t.getMessage());
+ }
+ }
+
+ /**
+ * Executes the selected query.
+ * @param conn the database connection
+ */
+ private static void executeQuery(Connection conn) throws SQLException
+ {
+ String author = select("Authors:", authors);
+ String publisher = select("Publishers:", publishers);
+ PreparedStatement stat;
+ if (!author.equals("Any") && !publisher.equals("Any"))
+ {
+ stat = conn.prepareStatement(authorPublisherQuery);
+ stat.setString(1, author);
+ stat.setString(2, publisher);
+ }
+ else if (!author.equals("Any") && publisher.equals("Any"))
+ {
+ stat = conn.prepareStatement(authorQuery);
+ stat.setString(1, author);
+ }
+ else if (author.equals("Any") && !publisher.equals("Any"))
+ {
+ stat = conn.prepareStatement(publisherQuery);
+ stat.setString(1, publisher);
+ }
+ else
+ stat = conn.prepareStatement(allQuery);
+
+ try (ResultSet rs = stat.executeQuery())
+ {
+ while (rs.next())
+ System.out.println(rs.getString(1) + ", " + rs.getString(2));
+ }
+ }
+
+ /**
+ * Executes an update statement to change prices.
+ * @param conn the database connection
+ */
+ public static void changePrices(Connection conn) throws SQLException
+ {
+ String publisher = select("Publishers:", publishers.subList(1, publishers.size()));
+ System.out.print("Change prices by: ");
+ double priceChange = in.nextDouble();
+ PreparedStatement stat = conn.prepareStatement(priceUpdate);
+ stat.setDouble(1, priceChange);
+ stat.setString(2, publisher);
+ int r = stat.executeUpdate();
+ System.out.println(r + " records updated.");
+ }
+
+ /**
+ * Asks the user to select a string.
+ * @param prompt the prompt to display
+ * @param options the options from which the user can choose
+ * @return the option that the user chose
+ */
+ public static String select(String prompt, List options)
+ {
+ while (true)
+ {
+ System.out.println(prompt);
+ for (int i = 0; i < options.size(); i++)
+ System.out.printf("%2d) %s%n", i + 1, options.get(i));
+ int sel = in.nextInt();
+ if (sel > 0 && sel <= options.size())
+ return options.get(sel - 1);
+ }
+ }
+
+ /**
+ * Gets a connection from the properties specified in the file database.properties.
+ * @return the database connection
+ */
+ public static Connection getConnection() throws SQLException, IOException
+ {
+ Properties props = new Properties();
+ try (InputStream in = Files.newInputStream(Paths.get("database.properties")))
+ {
+ props.load(in);
+ }
+
+ String drivers = props.getProperty("jdbc.drivers");
+ if (drivers != null) System.setProperty("jdbc.drivers", drivers);
+ String url = props.getProperty("jdbc.url");
+ String username = props.getProperty("jdbc.username");
+ String password = props.getProperty("jdbc.password");
+
+ return DriverManager.getConnection(url, username, password);
+ }
+}
diff --git a/corejava第10版/v2ch05/test/TestDB.java b/corejava第10版/v2ch05/test/TestDB.java
new file mode 100644
index 0000000..df1bd6a
--- /dev/null
+++ b/corejava第10版/v2ch05/test/TestDB.java
@@ -0,0 +1,69 @@
+package test;
+
+import java.nio.file.*;
+import java.sql.*;
+import java.io.*;
+import java.util.*;
+
+/**
+ * This program tests that the database and the JDBC driver are correctly configured.
+ * @version 1.02 2012-06-05
+ * @author Cay Horstmann
+ */
+public class TestDB
+{
+ public static void main(String args[]) throws IOException
+ {
+ try
+ {
+ runTest();
+ }
+ catch (SQLException ex)
+ {
+ for (Throwable t : ex)
+ t.printStackTrace();
+ }
+ }
+
+ /**
+ * Runs a test by creating a table, adding a value, showing the table contents, and removing
+ * the table.
+ */
+ public static void runTest() throws SQLException, IOException
+ {
+
+ try (Connection conn = getConnection();
+ Statement stat = conn.createStatement())
+ {
+ stat.executeUpdate("CREATE TABLE Greetings (Message CHAR(20))");
+ stat.executeUpdate("INSERT INTO Greetings VALUES ('Hello, World!')");
+
+ try (ResultSet result = stat.executeQuery("SELECT * FROM Greetings"))
+ {
+ if (result.next())
+ System.out.println(result.getString(1));
+ }
+ stat.executeUpdate("DROP TABLE Greetings");
+ }
+ }
+
+ /**
+ * Gets a connection from the properties specified in the file database.properties.
+ * @return the database connection
+ */
+ public static Connection getConnection() throws SQLException, IOException
+ {
+ Properties props = new Properties();
+ try (InputStream in = Files.newInputStream(Paths.get("database.properties")))
+ {
+ props.load(in);
+ }
+ String drivers = props.getProperty("jdbc.drivers");
+ if (drivers != null) System.setProperty("jdbc.drivers", drivers);
+ String url = props.getProperty("jdbc.url");
+ String username = props.getProperty("jdbc.username");
+ String password = props.getProperty("jdbc.password");
+
+ return DriverManager.getConnection(url, username, password);
+ }
+}
diff --git a/corejava第10版/v2ch05/view/ViewDB.java b/corejava第10版/v2ch05/view/ViewDB.java
new file mode 100644
index 0000000..523015d
--- /dev/null
+++ b/corejava第10版/v2ch05/view/ViewDB.java
@@ -0,0 +1,325 @@
+package view;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.nio.file.*;
+import java.sql.*;
+import java.util.*;
+
+import javax.sql.*;
+import javax.sql.rowset.*;
+import javax.swing.*;
+
+/**
+ * This program uses metadata to display arbitrary tables in a database.
+ * @version 1.33 2016-04-27
+ * @author Cay Horstmann
+ */
+public class ViewDB
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new ViewDBFrame();
+ frame.setTitle("ViewDB");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * The frame that holds the data panel and the navigation buttons.
+ */
+class ViewDBFrame extends JFrame
+{
+ private JButton previousButton;
+ private JButton nextButton;
+ private JButton deleteButton;
+ private JButton saveButton;
+ private DataPanel dataPanel;
+ private Component scrollPane;
+ private JComboBox tableNames;
+ private Properties props;
+ private CachedRowSet crs;
+ private Connection conn;
+
+ public ViewDBFrame()
+ {
+ tableNames = new JComboBox();
+
+ try
+ {
+ readDatabaseProperties();
+ conn = getConnection();
+ DatabaseMetaData meta = conn.getMetaData();
+ try (ResultSet mrs = meta.getTables(null, null, null, new String[] { "TABLE" }))
+ {
+ while (mrs.next())
+ tableNames.addItem(mrs.getString(3));
+ }
+ }
+ catch (SQLException ex)
+ {
+ for (Throwable t : ex)
+ t.printStackTrace();
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+
+ tableNames.addActionListener(
+ event -> showTable((String) tableNames.getSelectedItem(), conn));
+ add(tableNames, BorderLayout.NORTH);
+ addWindowListener(new WindowAdapter()
+ {
+ public void windowClosing(WindowEvent event)
+ {
+ try
+ {
+ if (conn != null) conn.close();
+ }
+ catch (SQLException ex)
+ {
+ for (Throwable t : ex)
+ t.printStackTrace();
+ }
+ }
+ });
+
+ JPanel buttonPanel = new JPanel();
+ add(buttonPanel, BorderLayout.SOUTH);
+
+ previousButton = new JButton("Previous");
+ previousButton.addActionListener(event -> showPreviousRow());
+ buttonPanel.add(previousButton);
+
+ nextButton = new JButton("Next");
+ nextButton.addActionListener(event -> showNextRow());
+ buttonPanel.add(nextButton);
+
+ deleteButton = new JButton("Delete");
+ deleteButton.addActionListener(event -> deleteRow());
+ buttonPanel.add(deleteButton);
+
+ saveButton = new JButton("Save");
+ saveButton.addActionListener(event -> saveChanges());
+ buttonPanel.add(saveButton);
+ if (tableNames.getItemCount() > 0)
+ showTable(tableNames.getItemAt(0), conn);
+ }
+
+ /**
+ * Prepares the text fields for showing a new table, and shows the first row.
+ * @param tableName the name of the table to display
+ * @param conn the database connection
+ */
+ public void showTable(String tableName, Connection conn)
+ {
+ try (Statement stat = conn.createStatement();
+ ResultSet result = stat.executeQuery("SELECT * FROM " + tableName))
+ {
+ // get result set
+
+ // copy into cached row set
+ RowSetFactory factory = RowSetProvider.newFactory();
+ crs = factory.createCachedRowSet();
+ crs.setTableName(tableName);
+ crs.populate(result);
+
+ if (scrollPane != null) remove(scrollPane);
+ dataPanel = new DataPanel(crs);
+ scrollPane = new JScrollPane(dataPanel);
+ add(scrollPane, BorderLayout.CENTER);
+ pack();
+ showNextRow();
+ }
+ catch (SQLException ex)
+ {
+ for (Throwable t : ex)
+ t.printStackTrace();
+ }
+ }
+
+ /**
+ * Moves to the previous table row.
+ */
+ public void showPreviousRow()
+ {
+ try
+ {
+ if (crs == null || crs.isFirst()) return;
+ crs.previous();
+ dataPanel.showRow(crs);
+ }
+ catch (SQLException ex)
+ {
+ for (Throwable t : ex)
+ t.printStackTrace();
+ }
+ }
+
+ /**
+ * Moves to the next table row.
+ */
+ public void showNextRow()
+ {
+ try
+ {
+ if (crs == null || crs.isLast()) return;
+ crs.next();
+ dataPanel.showRow(crs);
+ }
+ catch (SQLException ex)
+ {
+ for (Throwable t : ex)
+ t.printStackTrace();
+ }
+ }
+
+ /**
+ * Deletes current table row.
+ */
+ public void deleteRow()
+ {
+ if (crs == null) return;
+ new SwingWorker()
+ {
+ public Void doInBackground() throws SQLException
+ {
+ crs.deleteRow();
+ crs.acceptChanges(conn);
+ if (crs.isAfterLast())
+ if (!crs.last()) crs = null;
+ return null;
+ }
+ public void done()
+ {
+ dataPanel.showRow(crs);
+ }
+ }.execute();
+ }
+ /**
+ * Saves all changes.
+ */
+ public void saveChanges()
+ {
+ if (crs == null) return;
+ new SwingWorker()
+ {
+ public Void doInBackground() throws SQLException
+ {
+ dataPanel.setRow(crs);
+ crs.acceptChanges(conn);
+ return null;
+ }
+ }.execute();
+ }
+
+ private void readDatabaseProperties() throws IOException
+ {
+ props = new Properties();
+ try (InputStream in = Files.newInputStream(Paths.get("database.properties")))
+ {
+ props.load(in);
+ }
+ String drivers = props.getProperty("jdbc.drivers");
+ if (drivers != null) System.setProperty("jdbc.drivers", drivers);
+ }
+
+ /**
+ * Gets a connection from the properties specified in the file database.properties.
+ * @return the database connection
+ */
+ private Connection getConnection() throws SQLException
+ {
+ String url = props.getProperty("jdbc.url");
+ String username = props.getProperty("jdbc.username");
+ String password = props.getProperty("jdbc.password");
+
+ return DriverManager.getConnection(url, username, password);
+ }
+}
+
+/**
+ * This panel displays the contents of a result set.
+ */
+class DataPanel extends JPanel
+{
+ private java.util.List fields;
+
+ /**
+ * Constructs the data panel.
+ * @param rs the result set whose contents this panel displays
+ */
+ public DataPanel(RowSet rs) throws SQLException
+ {
+ fields = new ArrayList<>();
+ setLayout(new GridBagLayout());
+ GridBagConstraints gbc = new GridBagConstraints();
+ gbc.gridwidth = 1;
+ gbc.gridheight = 1;
+
+ ResultSetMetaData rsmd = rs.getMetaData();
+ for (int i = 1; i <= rsmd.getColumnCount(); i++)
+ {
+ gbc.gridy = i - 1;
+
+ String columnName = rsmd.getColumnLabel(i);
+ gbc.gridx = 0;
+ gbc.anchor = GridBagConstraints.EAST;
+ add(new JLabel(columnName), gbc);
+
+ int columnWidth = rsmd.getColumnDisplaySize(i);
+ JTextField tb = new JTextField(columnWidth);
+ if (!rsmd.getColumnClassName(i).equals("java.lang.String"))
+ tb.setEditable(false);
+
+ fields.add(tb);
+
+ gbc.gridx = 1;
+ gbc.anchor = GridBagConstraints.WEST;
+ add(tb, gbc);
+ }
+ }
+
+ /**
+ * Shows a database row by populating all text fields with the column values.
+ */
+ public void showRow(ResultSet rs)
+ {
+ try
+ {
+ if (rs == null) return;
+ for (int i = 1; i <= fields.size(); i++)
+ {
+ String field = rs == null ? "" : rs.getString(i);
+ JTextField tb = fields.get(i - 1);
+ tb.setText(field);
+ }
+ }
+ catch (SQLException ex)
+ {
+ for (Throwable t : ex)
+ t.printStackTrace();
+ }
+ }
+
+ /**
+ * Updates changed data into the current row of the row set.
+ */
+ public void setRow(RowSet rs) throws SQLException
+ {
+ for (int i = 1; i <= fields.size(); i++)
+ {
+ String field = rs.getString(i);
+ JTextField tb = fields.get(i - 1);
+ if (!field.equals(tb.getText()))
+ rs.updateString(i, tb.getText());
+ }
+ rs.updateRow();
+ }
+}
diff --git a/corejava第10版/v2ch06/formatting/Formatting.java b/corejava第10版/v2ch06/formatting/Formatting.java
new file mode 100644
index 0000000..9405d3c
--- /dev/null
+++ b/corejava第10版/v2ch06/formatting/Formatting.java
@@ -0,0 +1,41 @@
+package formatting;
+
+import java.time.*;
+import java.time.format.*;
+import java.util.*;
+
+public class Formatting
+{
+ public static void main(String[] args)
+ {
+ ZonedDateTime apollo11launch = ZonedDateTime.of(1969, 7, 16, 9, 32, 0, 0,
+ ZoneId.of("America/New_York"));
+
+ String formatted = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(apollo11launch);
+ // 1969-07-16T09:32:00-04:00
+ System.out.println(formatted);
+
+ DateTimeFormatter formatter = DateTimeFormatter
+ .ofLocalizedDateTime(FormatStyle.LONG);
+ formatted = formatter.format(apollo11launch);
+ // July 16, 1969 9:32:00 AM EDT
+ System.out.println(formatted);
+ formatted = formatter.withLocale(Locale.FRENCH).format(apollo11launch);
+ // 16 juillet 1969 09:32:00 EDT
+ System.out.println(formatted);
+
+ formatter = DateTimeFormatter.ofPattern("E yyyy-MM-dd HH:mm");
+ formatted = formatter.format(apollo11launch);
+ System.out.println(formatted);
+
+ LocalDate churchsBirthday = LocalDate.parse("1903-06-14");
+ System.out.println("churchsBirthday: " + churchsBirthday);
+ apollo11launch = ZonedDateTime.parse("1969-07-16 03:32:00-0400",
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssxx"));
+ System.out.println("apollo11launch: " + apollo11launch);
+
+ for (DayOfWeek w : DayOfWeek.values())
+ System.out.print(w.getDisplayName(TextStyle.SHORT, Locale.ENGLISH)
+ + " ");
+ }
+}
diff --git a/corejava第10版/v2ch06/localdates/LocalDates.java b/corejava第10版/v2ch06/localdates/LocalDates.java
new file mode 100644
index 0000000..028d12b
--- /dev/null
+++ b/corejava第10版/v2ch06/localdates/LocalDates.java
@@ -0,0 +1,38 @@
+package localdates;
+
+import java.time.*;
+import java.time.temporal.*;
+
+public class LocalDates
+{
+ public static void main(String[] args)
+ {
+ LocalDate today = LocalDate.now(); // Today’s date
+ System.out.println("today: " + today);
+
+ LocalDate alonzosBirthday = LocalDate.of(1903, 6, 14);
+ alonzosBirthday = LocalDate.of(1903, Month.JUNE, 14);
+ // Uses the Month enumeration
+ System.out.println("alonzosBirthday: " + alonzosBirthday);
+
+ LocalDate programmersDay = LocalDate.of(2018, 1, 1).plusDays(255);
+ // September 13, but in a leap year it would be September 12
+ System.out.println("programmersDay: " + programmersDay);
+
+ LocalDate independenceDay = LocalDate.of(2018, Month.JULY, 4);
+ LocalDate christmas = LocalDate.of(2018, Month.DECEMBER, 25);
+
+ System.out
+ .println("Until christmas: " + independenceDay.until(christmas));
+ System.out.println("Until christmas: "
+ + independenceDay.until(christmas, ChronoUnit.DAYS));
+
+ System.out.println(LocalDate.of(2016, 1, 31).plusMonths(1));
+ System.out.println(LocalDate.of(2016, 3, 31).minusMonths(1));
+
+ DayOfWeek startOfLastMillennium = LocalDate.of(1900, 1, 1).getDayOfWeek();
+ System.out.println("startOfLastMillennium: " + startOfLastMillennium);
+ System.out.println(startOfLastMillennium.getValue());
+ System.out.println(DayOfWeek.SATURDAY.plus(3));
+ }
+}
diff --git a/corejava第10版/v2ch06/timeline/Timeline.java b/corejava第10版/v2ch06/timeline/Timeline.java
new file mode 100644
index 0000000..a138946
--- /dev/null
+++ b/corejava第10版/v2ch06/timeline/Timeline.java
@@ -0,0 +1,48 @@
+package timeline;
+
+import java.time.*;
+import java.util.*;
+import java.util.stream.*;
+
+public class Timeline
+{
+ public static void main(String[] args)
+ {
+ Instant start = Instant.now();
+ runAlgorithm();
+ Instant end = Instant.now();
+ Duration timeElapsed = Duration.between(start, end);
+ long millis = timeElapsed.toMillis();
+ System.out.printf("%d milliseconds\n", millis);
+
+ Instant start2 = Instant.now();
+ runAlgorithm2();
+ Instant end2 = Instant.now();
+ Duration timeElapsed2 = Duration.between(start2, end2);
+ System.out.printf("%d milliseconds\n", timeElapsed2.toMillis());
+ boolean overTenTimesFaster = timeElapsed.multipliedBy(10)
+ .minus(timeElapsed2).isNegative();
+ System.out.printf("The first algorithm is %smore than ten times faster",
+ overTenTimesFaster ? "" : "not ");
+ }
+
+ public static void runAlgorithm()
+ {
+ int size = 10;
+ List list = new Random().ints().map(i -> i % 100).limit(size)
+ .boxed().collect(Collectors.toList());
+ Collections.sort(list);
+ System.out.println(list);
+ }
+
+ public static void runAlgorithm2()
+ {
+ int size = 10;
+ List list = new Random().ints().map(i -> i % 100).limit(size)
+ .boxed().collect(Collectors.toList());
+ while (!IntStream.range(1, list.size()).allMatch(
+ i -> list.get(i - 1).compareTo(list.get(i)) <= 0))
+ Collections.shuffle(list);
+ System.out.println(list);
+ }
+}
diff --git a/corejava第10版/v2ch06/zonedTimes/ZonedTimes.java b/corejava第10版/v2ch06/zonedTimes/ZonedTimes.java
new file mode 100644
index 0000000..230ec25
--- /dev/null
+++ b/corejava第10版/v2ch06/zonedTimes/ZonedTimes.java
@@ -0,0 +1,43 @@
+package zonedtimes;
+
+import java.time.*;
+
+public class ZonedTimes
+{
+ public static void main(String[] args)
+ {
+ ZonedDateTime apollo11launch = ZonedDateTime.of(1969, 7, 16, 9, 32, 0, 0,
+ ZoneId.of("America/New_York"));
+ // 1969-07-16T09:32-04:00[America/New_York]
+ System.out.println("apollo11launch: " + apollo11launch);
+
+ Instant instant = apollo11launch.toInstant();
+ System.out.println("instant: " + instant);
+
+ ZonedDateTime zonedDateTime = instant.atZone(ZoneId.of("UTC"));
+ System.out.println("zonedDateTime: " + zonedDateTime);
+
+ ZonedDateTime skipped = ZonedDateTime.of(LocalDate.of(2013, 3, 31),
+ LocalTime.of(2, 30), ZoneId.of("Europe/Berlin"));
+ // Constructs March 31 3:30
+ System.out.println("skipped: " + skipped);
+
+ ZonedDateTime ambiguous = ZonedDateTime.of(LocalDate.of(2013, 10, 27),
+ // End of daylight savings time
+ LocalTime.of(2, 30), ZoneId.of("Europe/Berlin"));
+ // 2013-10-27T02:30+02:00[Europe/Berlin]
+ ZonedDateTime anHourLater = ambiguous.plusHours(1);
+ // 2013-10-27T02:30+01:00[Europe/Berlin]
+ System.out.println("ambiguous: " + ambiguous);
+ System.out.println("anHourLater: " + anHourLater);
+
+ ZonedDateTime meeting = ZonedDateTime.of(LocalDate.of(2013, 10, 31),
+ LocalTime.of(14, 30), ZoneId.of("America/Los_Angeles"));
+ System.out.println("meeting: " + meeting);
+ ZonedDateTime nextMeeting = meeting.plus(Duration.ofDays(7));
+ // Caution! Won’t work with daylight savings time
+ System.out.println("nextMeeting: " + nextMeeting);
+ nextMeeting = meeting.plus(Period.ofDays(7)); // OK
+ System.out.println("nextMeeting: " + nextMeeting);
+ }
+}
diff --git a/corejava第10版/v2ch07/collation/CollationTest.java b/corejava第10版/v2ch07/collation/CollationTest.java
new file mode 100644
index 0000000..9eda392
--- /dev/null
+++ b/corejava第10版/v2ch07/collation/CollationTest.java
@@ -0,0 +1,120 @@
+package collation;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.text.*;
+import java.util.*;
+import java.util.List;
+
+import javax.swing.*;
+
+/**
+ * This program demonstrates collating strings under various locales.
+ * @version 1.15 2016-05-06
+ * @author Cay Horstmann
+ */
+public class CollationTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new CollationFrame();
+ frame.setTitle("CollationTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * This frame contains combo boxes to pick a locale, collation strength and decomposition rules, a
+ * text field and button to add new strings, and a text area to list the collated strings.
+ */
+class CollationFrame extends JFrame
+{
+ private Collator collator = Collator.getInstance(Locale.getDefault());
+ private List strings = new ArrayList<>();
+ private Collator currentCollator;
+ private Locale[] locales;
+ private JComboBox localeCombo = new JComboBox<>();
+ private JTextField newWord = new JTextField(20);
+ private JTextArea sortedWords = new JTextArea(20, 20);
+ private JButton addButton = new JButton("Add");
+ private EnumCombo strengthCombo = new EnumCombo<>(Collator.class, "Primary",
+ "Secondary", "Tertiary", "Identical");
+ private EnumCombo decompositionCombo = new EnumCombo<>(Collator.class,
+ "Canonical Decomposition", "Full Decomposition", "No Decomposition");
+
+ public CollationFrame()
+ {
+ setLayout(new GridBagLayout());
+ add(new JLabel("Locale"), new GBC(0, 0).setAnchor(GBC.EAST));
+ add(new JLabel("Strength"), new GBC(0, 1).setAnchor(GBC.EAST));
+ add(new JLabel("Decomposition"), new GBC(0, 2).setAnchor(GBC.EAST));
+ add(addButton, new GBC(0, 3).setAnchor(GBC.EAST));
+ add(localeCombo, new GBC(1, 0).setAnchor(GBC.WEST));
+ add(strengthCombo, new GBC(1, 1).setAnchor(GBC.WEST));
+ add(decompositionCombo, new GBC(1, 2).setAnchor(GBC.WEST));
+ add(newWord, new GBC(1, 3).setFill(GBC.HORIZONTAL));
+ add(new JScrollPane(sortedWords), new GBC(0, 4, 2, 1).setFill(GBC.BOTH));
+
+ locales = (Locale[]) Collator.getAvailableLocales().clone();
+ Arrays.sort(locales, (l1, l2) -> collator.compare(l1.getDisplayName(), l2.getDisplayName()));
+ for (Locale loc : locales)
+ localeCombo.addItem(loc.getDisplayName());
+ localeCombo.setSelectedItem(Locale.getDefault().getDisplayName());
+
+ strings.add("America");
+ strings.add("able");
+ strings.add("Zulu");
+ strings.add("zebra");
+ strings.add("\u00C5ngstr\u00F6m");
+ strings.add("A\u030angstro\u0308m");
+ strings.add("Angstrom");
+ strings.add("Able");
+ strings.add("office");
+ strings.add("o\uFB03ce");
+ strings.add("Java\u2122");
+ strings.add("JavaTM");
+ updateDisplay();
+
+ addButton.addActionListener(event ->
+ {
+ strings.add(newWord.getText());
+ updateDisplay();
+ });
+
+ ActionListener listener = event -> updateDisplay();
+
+ localeCombo.addActionListener(listener);
+ strengthCombo.addActionListener(listener);
+ decompositionCombo.addActionListener(listener);
+ pack();
+ }
+
+ /**
+ * Updates the display and collates the strings according to the user settings.
+ */
+ public void updateDisplay()
+ {
+ Locale currentLocale = locales[localeCombo.getSelectedIndex()];
+ localeCombo.setLocale(currentLocale);
+
+ currentCollator = Collator.getInstance(currentLocale);
+ currentCollator.setStrength(strengthCombo.getValue());
+ currentCollator.setDecomposition(decompositionCombo.getValue());
+
+ strings.sort(currentCollator);
+
+ sortedWords.setText("");
+ for (int i = 0; i < strings.size(); i++)
+ {
+ String s = strings.get(i);
+ if (i > 0 && currentCollator.compare(s, strings.get(i - 1)) == 0) sortedWords
+ .append("= ");
+ sortedWords.append(s + "\n");
+ }
+ pack();
+ }
+}
diff --git a/javacore第11版/corejava/v2ch07/collation/EnumCombo.java b/corejava第10版/v2ch07/collation/EnumCombo.java
similarity index 100%
rename from javacore第11版/corejava/v2ch07/collation/EnumCombo.java
rename to corejava第10版/v2ch07/collation/EnumCombo.java
diff --git a/javacore第11版/corejava/v2ch07/collation/GBC.java b/corejava第10版/v2ch07/collation/GBC.java
similarity index 100%
rename from javacore第11版/corejava/v2ch07/collation/GBC.java
rename to corejava第10版/v2ch07/collation/GBC.java
diff --git a/corejava第10版/v2ch07/dateFormat/DateTimeFormatterTest.java b/corejava第10版/v2ch07/dateFormat/DateTimeFormatterTest.java
new file mode 100644
index 0000000..1332040
--- /dev/null
+++ b/corejava第10版/v2ch07/dateFormat/DateTimeFormatterTest.java
@@ -0,0 +1,159 @@
+package dateFormat;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.time.*;
+import java.time.format.*;
+import java.util.*;
+
+import javax.swing.*;
+
+/**
+ * This program demonstrates formatting dates under various locales.
+ * @version 1.00 2016-05-06
+ * @author Cay Horstmann
+ */
+public class DateTimeFormatterTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new DateTimeFormatterFrame();
+ frame.setTitle("DateFormatTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * This frame contains combo boxes to pick a locale, date and time formats, text fields to display
+ * formatted date and time, buttons to parse the text field contents, and a "lenient" check box.
+ */
+class DateTimeFormatterFrame extends JFrame
+{
+ private Locale[] locales;
+ private LocalDate currentDate;
+ private LocalTime currentTime;
+ private ZonedDateTime currentDateTime;
+ private DateTimeFormatter currentDateFormat;
+ private DateTimeFormatter currentTimeFormat;
+ private DateTimeFormatter currentDateTimeFormat;
+ private JComboBox localeCombo = new JComboBox<>();
+ private JButton dateParseButton = new JButton("Parse");
+ private JButton timeParseButton = new JButton("Parse");
+ private JButton dateTimeParseButton = new JButton("Parse");
+ private JTextField dateText = new JTextField(30);
+ private JTextField timeText = new JTextField(30);
+ private JTextField dateTimeText = new JTextField(30);
+ private EnumCombo dateStyleCombo = new EnumCombo<>(FormatStyle.class,
+ "Short", "Medium", "Long", "Full");
+ private EnumCombo timeStyleCombo = new EnumCombo<>(FormatStyle.class,
+ "Short", "Medium");
+ private EnumCombo dateTimeStyleCombo = new EnumCombo<>(FormatStyle.class,
+ "Short", "Medium", "Long", "Full");
+
+ public DateTimeFormatterFrame()
+ {
+ setLayout(new GridBagLayout());
+ add(new JLabel("Locale"), new GBC(0, 0).setAnchor(GBC.EAST));
+ add(localeCombo, new GBC(1, 0, 2, 1).setAnchor(GBC.WEST));
+
+ add(new JLabel("Date"), new GBC(0, 1).setAnchor(GBC.EAST));
+ add(dateStyleCombo, new GBC(1, 1).setAnchor(GBC.WEST));
+ add(dateText, new GBC(2, 1, 2, 1).setFill(GBC.HORIZONTAL));
+ add(dateParseButton, new GBC(4, 1).setAnchor(GBC.WEST));
+
+ add(new JLabel("Time"), new GBC(0, 2).setAnchor(GBC.EAST));
+ add(timeStyleCombo, new GBC(1, 2).setAnchor(GBC.WEST));
+ add(timeText, new GBC(2, 2, 2, 1).setFill(GBC.HORIZONTAL));
+ add(timeParseButton, new GBC(4, 2).setAnchor(GBC.WEST));
+
+ add(new JLabel("Date and time"), new GBC(0, 3).setAnchor(GBC.EAST));
+ add(dateTimeStyleCombo, new GBC(1, 3).setAnchor(GBC.WEST));
+ add(dateTimeText, new GBC(2, 3, 2, 1).setFill(GBC.HORIZONTAL));
+ add(dateTimeParseButton, new GBC(4, 3).setAnchor(GBC.WEST));
+
+ locales = (Locale[]) Locale.getAvailableLocales().clone();
+ Arrays.sort(locales, Comparator.comparing(Locale::getDisplayName));
+ for (Locale loc : locales)
+ localeCombo.addItem(loc.getDisplayName());
+ localeCombo.setSelectedItem(Locale.getDefault().getDisplayName());
+ currentDate = LocalDate.now();
+ currentTime = LocalTime.now();
+ currentDateTime = ZonedDateTime.now();
+ updateDisplay();
+
+ ActionListener listener = event -> updateDisplay();
+
+ localeCombo.addActionListener(listener);
+ dateStyleCombo.addActionListener(listener);
+ timeStyleCombo.addActionListener(listener);
+ dateTimeStyleCombo.addActionListener(listener);
+
+ dateParseButton.addActionListener(event ->
+ {
+ String d = dateText.getText().trim();
+ try
+ {
+ currentDate = LocalDate.parse(d, currentDateFormat);
+ updateDisplay();
+ }
+ catch (Exception e)
+ {
+ dateText.setText(e.getMessage());
+ }
+ });
+
+ timeParseButton.addActionListener(event ->
+ {
+ String t = timeText.getText().trim();
+ try
+ {
+ currentTime = LocalTime.parse(t, currentTimeFormat);
+ updateDisplay();
+ }
+ catch (Exception e)
+ {
+ timeText.setText(e.getMessage());
+ }
+ });
+
+ dateTimeParseButton.addActionListener(event ->
+ {
+ String t = dateTimeText.getText().trim();
+ try
+ {
+ currentDateTime = ZonedDateTime.parse(t, currentDateTimeFormat);
+ updateDisplay();
+ }
+ catch (Exception e)
+ {
+ dateTimeText.setText(e.getMessage());
+ }
+ });
+
+ pack();
+ }
+
+ /**
+ * Updates the display and formats the date according to the user settings.
+ */
+ public void updateDisplay()
+ {
+ Locale currentLocale = locales[localeCombo.getSelectedIndex()];
+ FormatStyle dateStyle = dateStyleCombo.getValue();
+ currentDateFormat = DateTimeFormatter.ofLocalizedDate(
+ dateStyle).withLocale(currentLocale);
+ dateText.setText(currentDateFormat.format(currentDate));
+ FormatStyle timeStyle = timeStyleCombo.getValue();
+ currentTimeFormat = DateTimeFormatter.ofLocalizedTime(
+ timeStyle).withLocale(currentLocale);
+ timeText.setText(currentTimeFormat.format(currentTime));
+ FormatStyle dateTimeStyle = dateTimeStyleCombo.getValue();
+ currentDateTimeFormat = DateTimeFormatter.ofLocalizedDateTime(
+ dateTimeStyle).withLocale(currentLocale);
+ dateTimeText.setText(currentDateTimeFormat.format(currentDateTime));
+ }
+}
diff --git a/javacore第11版/corejava/v2ch07/dateFormat/EnumCombo.java b/corejava第10版/v2ch07/dateFormat/EnumCombo.java
similarity index 100%
rename from javacore第11版/corejava/v2ch07/dateFormat/EnumCombo.java
rename to corejava第10版/v2ch07/dateFormat/EnumCombo.java
diff --git a/javacore第11版/corejava/v2ch07/dateFormat/GBC.java b/corejava第10版/v2ch07/dateFormat/GBC.java
similarity index 100%
rename from javacore第11版/corejava/v2ch07/dateFormat/GBC.java
rename to corejava第10版/v2ch07/dateFormat/GBC.java
diff --git a/javacore第11版/corejava/v2ch07/numberFormat/GBC.java b/corejava第10版/v2ch07/numberFormat/GBC.java
similarity index 100%
rename from javacore第11版/corejava/v2ch07/numberFormat/GBC.java
rename to corejava第10版/v2ch07/numberFormat/GBC.java
diff --git a/corejava第10版/v2ch07/numberFormat/NumberFormatTest.java b/corejava第10版/v2ch07/numberFormat/NumberFormatTest.java
new file mode 100644
index 0000000..9fc5886
--- /dev/null
+++ b/corejava第10版/v2ch07/numberFormat/NumberFormatTest.java
@@ -0,0 +1,127 @@
+package numberFormat;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.text.*;
+import java.util.*;
+
+import javax.swing.*;
+
+/**
+ * This program demonstrates formatting numbers under various locales.
+ * @version 1.14 2016-05-06
+ * @author Cay Horstmann
+ */
+public class NumberFormatTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new NumberFormatFrame();
+ frame.setTitle("NumberFormatTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * This frame contains radio buttons to select a number format, a combo box to pick a locale, a text
+ * field to display a formatted number, and a button to parse the text field contents.
+ */
+class NumberFormatFrame extends JFrame
+{
+ private Locale[] locales;
+ private double currentNumber;
+ private JComboBox localeCombo = new JComboBox<>();
+ private JButton parseButton = new JButton("Parse");
+ private JTextField numberText = new JTextField(30);
+ private JRadioButton numberRadioButton = new JRadioButton("Number");
+ private JRadioButton currencyRadioButton = new JRadioButton("Currency");
+ private JRadioButton percentRadioButton = new JRadioButton("Percent");
+ private ButtonGroup rbGroup = new ButtonGroup();
+ private NumberFormat currentNumberFormat;
+
+ public NumberFormatFrame()
+ {
+ setLayout(new GridBagLayout());
+
+ ActionListener listener = event -> updateDisplay();
+
+ JPanel p = new JPanel();
+ addRadioButton(p, numberRadioButton, rbGroup, listener);
+ addRadioButton(p, currencyRadioButton, rbGroup, listener);
+ addRadioButton(p, percentRadioButton, rbGroup, listener);
+
+ add(new JLabel("Locale:"), new GBC(0, 0).setAnchor(GBC.EAST));
+ add(p, new GBC(1, 1));
+ add(parseButton, new GBC(0, 2).setInsets(2));
+ add(localeCombo, new GBC(1, 0).setAnchor(GBC.WEST));
+ add(numberText, new GBC(1, 2).setFill(GBC.HORIZONTAL));
+ locales = (Locale[]) NumberFormat.getAvailableLocales().clone();
+ Arrays.sort(locales, Comparator.comparing(Locale::getDisplayName));
+ for (Locale loc : locales)
+ localeCombo.addItem(loc.getDisplayName());
+ localeCombo.setSelectedItem(Locale.getDefault().getDisplayName());
+ currentNumber = 123456.78;
+ updateDisplay();
+
+ localeCombo.addActionListener(listener);
+
+ parseButton.addActionListener(event ->
+ {
+ String s = numberText.getText().trim();
+ try
+ {
+ Number n = currentNumberFormat.parse(s);
+ if (n != null)
+ {
+ currentNumber = n.doubleValue();
+ updateDisplay();
+ }
+ else
+ {
+ numberText.setText("Parse error: " + s);
+ }
+ }
+ catch (ParseException e)
+ {
+ numberText.setText("Parse error: " + s);
+ }
+ });
+ pack();
+ }
+
+ /**
+ * Adds a radio button to a container.
+ * @param p the container into which to place the button
+ * @param b the button
+ * @param g the button group
+ * @param listener the button listener
+ */
+ public void addRadioButton(Container p, JRadioButton b, ButtonGroup g, ActionListener listener)
+ {
+ b.setSelected(g.getButtonCount() == 0);
+ b.addActionListener(listener);
+ g.add(b);
+ p.add(b);
+ }
+
+ /**
+ * Updates the display and formats the number according to the user settings.
+ */
+ public void updateDisplay()
+ {
+ Locale currentLocale = locales[localeCombo.getSelectedIndex()];
+ currentNumberFormat = null;
+ if (numberRadioButton.isSelected())
+ currentNumberFormat = NumberFormat.getNumberInstance(currentLocale);
+ else if (currencyRadioButton.isSelected())
+ currentNumberFormat = NumberFormat.getCurrencyInstance(currentLocale);
+ else if (percentRadioButton.isSelected())
+ currentNumberFormat = NumberFormat.getPercentInstance(currentLocale);
+ String formatted = currentNumberFormat.format(currentNumber);
+ numberText.setText(formatted);
+ }
+}
diff --git a/javacore第11版/corejava/v2ch07/retire/GBC.java b/corejava第10版/v2ch07/retire/GBC.java
similarity index 100%
rename from javacore第11版/corejava/v2ch07/retire/GBC.java
rename to corejava第10版/v2ch07/retire/GBC.java
diff --git a/corejava第10版/v2ch07/retire/LocaleCombo.java b/corejava第10版/v2ch07/retire/LocaleCombo.java
new file mode 100644
index 0000000..8fb6596
--- /dev/null
+++ b/corejava第10版/v2ch07/retire/LocaleCombo.java
@@ -0,0 +1,99 @@
+package retire;
+
+import java.text.*;
+import java.util.*;
+
+import javax.swing.*;
+import javax.swing.event.*;
+
+/**
+ * This combo box lets a user pick a locale. The locales are displayed in the locale of the combo
+ * box, and sorted according to the collator of the display locale.
+ * @version 1.01 2016-05-06
+ * @author Cay Horstmann
+ */
+public class LocaleCombo extends JComboBox
+{
+ private int selected;
+ private Locale[] locales;
+ private ListCellRenderer renderer;
+
+ /**
+ * Constructs a locale combo that displays an immutable collection of locales.
+ * @param locales the locales to display in this combo box
+ */
+ public LocaleCombo(Locale[] locales)
+ {
+ this.locales = (Locale[]) locales.clone();
+ sort();
+ setSelectedItem(getLocale());
+ }
+
+ public void setLocale(Locale newValue)
+ {
+ super.setLocale(newValue);
+ sort();
+ }
+
+ private void sort()
+ {
+ Locale loc = getLocale();
+ Collator collator = Collator.getInstance(loc);
+ Comparator comp =
+ (a, b) -> collator.compare(a.getDisplayName(loc), b.getDisplayName(loc));
+ Arrays.sort(locales, comp);
+ setModel(new ComboBoxModel()
+ {
+ public Locale getElementAt(int i)
+ {
+ return locales[i];
+ }
+
+ public int getSize()
+ {
+ return locales.length;
+ }
+
+ public void addListDataListener(ListDataListener l)
+ {
+ }
+
+ public void removeListDataListener(ListDataListener l)
+ {
+ }
+
+ public Locale getSelectedItem()
+ {
+ return selected >= 0 ? locales[selected] : null;
+ }
+
+ public void setSelectedItem(Object anItem)
+ {
+ if (anItem == null) selected = -1;
+ else selected = Arrays.binarySearch(locales, (Locale) anItem, comp);
+ }
+
+ });
+ setSelectedItem(selected);
+ }
+
+ public ListCellRenderer getRenderer()
+ {
+ if (renderer == null)
+ {
+ @SuppressWarnings("unchecked") final ListCellRenderer originalRenderer
+ = (ListCellRenderer) super.getRenderer();
+ if (originalRenderer == null) return null;
+ renderer = (list, value, index, isSelected, cellHasFocus) ->
+ originalRenderer.getListCellRendererComponent(list, value.getDisplayName(getLocale()),
+ index, isSelected, cellHasFocus);
+ }
+ return renderer;
+ }
+
+ public void setRenderer(ListCellRenderer super Locale> newValue)
+ {
+ renderer = null;
+ super.setRenderer(newValue);
+ }
+}
diff --git a/corejava第10版/v2ch07/retire/Retire.java b/corejava第10版/v2ch07/retire/Retire.java
new file mode 100644
index 0000000..3a614c9
--- /dev/null
+++ b/corejava第10版/v2ch07/retire/Retire.java
@@ -0,0 +1,516 @@
+package retire;
+
+import java.awt.*;
+import java.awt.geom.*;
+import java.text.*;
+import java.util.*;
+
+import javax.swing.*;
+
+/**
+ * This program shows a retirement calculator. The UI is displayed in English, German, and Chinese.
+ * @version 1.24 2016-05-06
+ * @author Cay Horstmann
+ */
+public class Retire
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new RetireFrame();
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+class RetireFrame extends JFrame
+{
+ private JTextField savingsField = new JTextField(10);
+ private JTextField contribField = new JTextField(10);
+ private JTextField incomeField = new JTextField(10);
+ private JTextField currentAgeField = new JTextField(4);
+ private JTextField retireAgeField = new JTextField(4);
+ private JTextField deathAgeField = new JTextField(4);
+ private JTextField inflationPercentField = new JTextField(6);
+ private JTextField investPercentField = new JTextField(6);
+ private JTextArea retireText = new JTextArea(10, 25);
+ private RetireComponent retireCanvas = new RetireComponent();
+ private JButton computeButton = new JButton();
+ private JLabel languageLabel = new JLabel();
+ private JLabel savingsLabel = new JLabel();
+ private JLabel contribLabel = new JLabel();
+ private JLabel incomeLabel = new JLabel();
+ private JLabel currentAgeLabel = new JLabel();
+ private JLabel retireAgeLabel = new JLabel();
+ private JLabel deathAgeLabel = new JLabel();
+ private JLabel inflationPercentLabel = new JLabel();
+ private JLabel investPercentLabel = new JLabel();
+ private RetireInfo info = new RetireInfo();
+ private Locale[] locales = { Locale.US, Locale.CHINA, Locale.GERMANY };
+ private Locale currentLocale;
+ private JComboBox localeCombo = new LocaleCombo(locales);
+ private ResourceBundle res;
+ private ResourceBundle resStrings;
+ private NumberFormat currencyFmt;
+ private NumberFormat numberFmt;
+ private NumberFormat percentFmt;
+
+ public RetireFrame()
+ {
+ setLayout(new GridBagLayout());
+ add(languageLabel, new GBC(0, 0).setAnchor(GBC.EAST));
+ add(savingsLabel, new GBC(0, 1).setAnchor(GBC.EAST));
+ add(contribLabel, new GBC(2, 1).setAnchor(GBC.EAST));
+ add(incomeLabel, new GBC(4, 1).setAnchor(GBC.EAST));
+ add(currentAgeLabel, new GBC(0, 2).setAnchor(GBC.EAST));
+ add(retireAgeLabel, new GBC(2, 2).setAnchor(GBC.EAST));
+ add(deathAgeLabel, new GBC(4, 2).setAnchor(GBC.EAST));
+ add(inflationPercentLabel, new GBC(0, 3).setAnchor(GBC.EAST));
+ add(investPercentLabel, new GBC(2, 3).setAnchor(GBC.EAST));
+ add(localeCombo, new GBC(1, 0, 3, 1));
+ add(savingsField, new GBC(1, 1).setWeight(100, 0).setFill(GBC.HORIZONTAL));
+ add(contribField, new GBC(3, 1).setWeight(100, 0).setFill(GBC.HORIZONTAL));
+ add(incomeField, new GBC(5, 1).setWeight(100, 0).setFill(GBC.HORIZONTAL));
+ add(currentAgeField, new GBC(1, 2).setWeight(100, 0).setFill(GBC.HORIZONTAL));
+ add(retireAgeField, new GBC(3, 2).setWeight(100, 0).setFill(GBC.HORIZONTAL));
+ add(deathAgeField, new GBC(5, 2).setWeight(100, 0).setFill(GBC.HORIZONTAL));
+ add(inflationPercentField, new GBC(1, 3).setWeight(100, 0).setFill(GBC.HORIZONTAL));
+ add(investPercentField, new GBC(3, 3).setWeight(100, 0).setFill(GBC.HORIZONTAL));
+ add(retireCanvas, new GBC(0, 4, 4, 1).setWeight(100, 100).setFill(GBC.BOTH));
+ add(new JScrollPane(retireText), new GBC(4, 4, 2, 1).setWeight(0, 100).setFill(GBC.BOTH));
+
+ computeButton.setName("computeButton");
+ computeButton.addActionListener(event ->
+ {
+ getInfo();
+ updateData();
+ updateGraph();
+ });
+ add(computeButton, new GBC(5, 3));
+
+ retireText.setEditable(false);
+ retireText.setFont(new Font("Monospaced", Font.PLAIN, 10));
+
+ info.setSavings(0);
+ info.setContrib(9000);
+ info.setIncome(60000);
+ info.setCurrentAge(35);
+ info.setRetireAge(65);
+ info.setDeathAge(85);
+ info.setInvestPercent(0.1);
+ info.setInflationPercent(0.05);
+
+ int localeIndex = 0; // US locale is default selection
+ for (int i = 0; i < locales.length; i++)
+ // if current locale one of the choices, select it
+ if (getLocale().equals(locales[i])) localeIndex = i;
+ setCurrentLocale(locales[localeIndex]);
+
+ localeCombo.addActionListener(event ->
+ {
+ setCurrentLocale((Locale) localeCombo.getSelectedItem());
+ validate();
+ });
+ pack();
+ }
+
+ /**
+ * Sets the current locale.
+ * @param locale the desired locale
+ */
+ public void setCurrentLocale(Locale locale)
+ {
+ currentLocale = locale;
+ localeCombo.setLocale(currentLocale);
+ localeCombo.setSelectedItem(currentLocale);
+
+ res = ResourceBundle.getBundle("retire.RetireResources", currentLocale);
+ resStrings = ResourceBundle.getBundle("retire.RetireStrings", currentLocale);
+ currencyFmt = NumberFormat.getCurrencyInstance(currentLocale);
+ numberFmt = NumberFormat.getNumberInstance(currentLocale);
+ percentFmt = NumberFormat.getPercentInstance(currentLocale);
+
+ updateDisplay();
+ updateInfo();
+ updateData();
+ updateGraph();
+ }
+
+ /**
+ * Updates all labels in the display.
+ */
+ public void updateDisplay()
+ {
+ languageLabel.setText(resStrings.getString("language"));
+ savingsLabel.setText(resStrings.getString("savings"));
+ contribLabel.setText(resStrings.getString("contrib"));
+ incomeLabel.setText(resStrings.getString("income"));
+ currentAgeLabel.setText(resStrings.getString("currentAge"));
+ retireAgeLabel.setText(resStrings.getString("retireAge"));
+ deathAgeLabel.setText(resStrings.getString("deathAge"));
+ inflationPercentLabel.setText(resStrings.getString("inflationPercent"));
+ investPercentLabel.setText(resStrings.getString("investPercent"));
+ computeButton.setText(resStrings.getString("computeButton"));
+ }
+
+ /**
+ * Updates the information in the text fields.
+ */
+ public void updateInfo()
+ {
+ savingsField.setText(currencyFmt.format(info.getSavings()));
+ contribField.setText(currencyFmt.format(info.getContrib()));
+ incomeField.setText(currencyFmt.format(info.getIncome()));
+ currentAgeField.setText(numberFmt.format(info.getCurrentAge()));
+ retireAgeField.setText(numberFmt.format(info.getRetireAge()));
+ deathAgeField.setText(numberFmt.format(info.getDeathAge()));
+ investPercentField.setText(percentFmt.format(info.getInvestPercent()));
+ inflationPercentField.setText(percentFmt.format(info.getInflationPercent()));
+ }
+
+ /**
+ * Updates the data displayed in the text area.
+ */
+ public void updateData()
+ {
+ retireText.setText("");
+ MessageFormat retireMsg = new MessageFormat("");
+ retireMsg.setLocale(currentLocale);
+ retireMsg.applyPattern(resStrings.getString("retire"));
+
+ for (int i = info.getCurrentAge(); i <= info.getDeathAge(); i++)
+ {
+ Object[] args = { i, info.getBalance(i) };
+ retireText.append(retireMsg.format(args) + "\n");
+ }
+ }
+
+ /**
+ * Updates the graph.
+ */
+ public void updateGraph()
+ {
+ retireCanvas.setColorPre((Color) res.getObject("colorPre"));
+ retireCanvas.setColorGain((Color) res.getObject("colorGain"));
+ retireCanvas.setColorLoss((Color) res.getObject("colorLoss"));
+ retireCanvas.setInfo(info);
+ repaint();
+ }
+
+ /**
+ * Reads the user input from the text fields.
+ */
+ public void getInfo()
+ {
+ try
+ {
+ info.setSavings(currencyFmt.parse(savingsField.getText()).doubleValue());
+ info.setContrib(currencyFmt.parse(contribField.getText()).doubleValue());
+ info.setIncome(currencyFmt.parse(incomeField.getText()).doubleValue());
+ info.setCurrentAge(numberFmt.parse(currentAgeField.getText()).intValue());
+ info.setRetireAge(numberFmt.parse(retireAgeField.getText()).intValue());
+ info.setDeathAge(numberFmt.parse(deathAgeField.getText()).intValue());
+ info.setInvestPercent(percentFmt.parse(investPercentField.getText()).doubleValue());
+ info.setInflationPercent(percentFmt.parse(inflationPercentField.getText()).doubleValue());
+ }
+ catch (ParseException ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
+
+/**
+ * The information required to compute retirement income data.
+ */
+class RetireInfo
+{
+ private double savings;
+ private double contrib;
+ private double income;
+ private int currentAge;
+ private int retireAge;
+ private int deathAge;
+ private double inflationPercent;
+ private double investPercent;
+ private int age;
+ private double balance;
+
+ /**
+ * Gets the available balance for a given year.
+ * @param year the year for which to compute the balance
+ * @return the amount of money available (or required) in that year
+ */
+ public double getBalance(int year)
+ {
+ if (year < currentAge) return 0;
+ else if (year == currentAge)
+ {
+ age = year;
+ balance = savings;
+ return balance;
+ }
+ else if (year == age) return balance;
+ if (year != age + 1) getBalance(year - 1);
+ age = year;
+ if (age < retireAge) balance += contrib;
+ else balance -= income;
+ balance = balance * (1 + (investPercent - inflationPercent));
+ return balance;
+ }
+
+ /**
+ * Gets the amount of prior savings.
+ * @return the savings amount
+ */
+ public double getSavings()
+ {
+ return savings;
+ }
+
+ /**
+ * Sets the amount of prior savings.
+ * @param newValue the savings amount
+ */
+ public void setSavings(double newValue)
+ {
+ savings = newValue;
+ }
+
+ /**
+ * Gets the annual contribution to the retirement account.
+ * @return the contribution amount
+ */
+ public double getContrib()
+ {
+ return contrib;
+ }
+
+ /**
+ * Sets the annual contribution to the retirement account.
+ * @param newValue the contribution amount
+ */
+ public void setContrib(double newValue)
+ {
+ contrib = newValue;
+ }
+
+ /**
+ * Gets the annual income.
+ * @return the income amount
+ */
+ public double getIncome()
+ {
+ return income;
+ }
+
+ /**
+ * Sets the annual income.
+ * @param newValue the income amount
+ */
+ public void setIncome(double newValue)
+ {
+ income = newValue;
+ }
+
+ /**
+ * Gets the current age.
+ * @return the age
+ */
+ public int getCurrentAge()
+ {
+ return currentAge;
+ }
+
+ /**
+ * Sets the current age.
+ * @param newValue the age
+ */
+ public void setCurrentAge(int newValue)
+ {
+ currentAge = newValue;
+ }
+
+ /**
+ * Gets the desired retirement age.
+ * @return the age
+ */
+ public int getRetireAge()
+ {
+ return retireAge;
+ }
+
+ /**
+ * Sets the desired retirement age.
+ * @param newValue the age
+ */
+ public void setRetireAge(int newValue)
+ {
+ retireAge = newValue;
+ }
+
+ /**
+ * Gets the expected age of death.
+ * @return the age
+ */
+ public int getDeathAge()
+ {
+ return deathAge;
+ }
+
+ /**
+ * Sets the expected age of death.
+ * @param newValue the age
+ */
+ public void setDeathAge(int newValue)
+ {
+ deathAge = newValue;
+ }
+
+ /**
+ * Gets the estimated percentage of inflation.
+ * @return the percentage
+ */
+ public double getInflationPercent()
+ {
+ return inflationPercent;
+ }
+
+ /**
+ * Sets the estimated percentage of inflation.
+ * @param newValue the percentage
+ */
+ public void setInflationPercent(double newValue)
+ {
+ inflationPercent = newValue;
+ }
+
+ /**
+ * Gets the estimated yield of the investment.
+ * @return the percentage
+ */
+ public double getInvestPercent()
+ {
+ return investPercent;
+ }
+
+ /**
+ * Sets the estimated yield of the investment.
+ * @param newValue the percentage
+ */
+ public void setInvestPercent(double newValue)
+ {
+ investPercent = newValue;
+ }
+}
+
+/**
+ * This component draws a graph of the investment result.
+ */
+class RetireComponent extends JComponent
+{
+ private static final int PANEL_WIDTH = 400;
+ private static final int PANEL_HEIGHT = 200;
+ private static final Dimension PREFERRED_SIZE = new Dimension(800, 600);
+ private RetireInfo info = null;
+ private Color colorPre;
+ private Color colorGain;
+ private Color colorLoss;
+
+ public RetireComponent()
+ {
+ setSize(PANEL_WIDTH, PANEL_HEIGHT);
+ }
+
+ /**
+ * Sets the retirement information to be plotted.
+ * @param newInfo the new retirement info.
+ */
+ public void setInfo(RetireInfo newInfo)
+ {
+ info = newInfo;
+ repaint();
+ }
+
+ public void paintComponent(Graphics g)
+ {
+ Graphics2D g2 = (Graphics2D) g;
+ if (info == null) return;
+
+ double minValue = 0;
+ double maxValue = 0;
+ int i;
+ for (i = info.getCurrentAge(); i <= info.getDeathAge(); i++)
+ {
+ double v = info.getBalance(i);
+ if (minValue > v) minValue = v;
+ if (maxValue < v) maxValue = v;
+ }
+ if (maxValue == minValue) return;
+
+ int barWidth = getWidth() / (info.getDeathAge() - info.getCurrentAge() + 1);
+ double scale = getHeight() / (maxValue - minValue);
+
+ for (i = info.getCurrentAge(); i <= info.getDeathAge(); i++)
+ {
+ int x1 = (i - info.getCurrentAge()) * barWidth + 1;
+ int y1;
+ double v = info.getBalance(i);
+ int height;
+ int yOrigin = (int) (maxValue * scale);
+
+ if (v >= 0)
+ {
+ y1 = (int) ((maxValue - v) * scale);
+ height = yOrigin - y1;
+ }
+ else
+ {
+ y1 = yOrigin;
+ height = (int) (-v * scale);
+ }
+
+ if (i < info.getRetireAge()) g2.setPaint(colorPre);
+ else if (v >= 0) g2.setPaint(colorGain);
+ else g2.setPaint(colorLoss);
+ Rectangle2D bar = new Rectangle2D.Double(x1, y1, barWidth - 2, height);
+ g2.fill(bar);
+ g2.setPaint(Color.black);
+ g2.draw(bar);
+ }
+ }
+
+ /**
+ * Sets the color to be used before retirement.
+ * @param color the desired color
+ */
+ public void setColorPre(Color color)
+ {
+ colorPre = color;
+ repaint();
+ }
+
+ /**
+ * Sets the color to be used after retirement while the account balance is positive.
+ * @param color the desired color
+ */
+ public void setColorGain(Color color)
+ {
+ colorGain = color;
+ repaint();
+ }
+
+ /**
+ * Sets the color to be used after retirement when the account balance is negative.
+ * @param color the desired color
+ */
+ public void setColorLoss(Color color)
+ {
+ colorLoss = color;
+ repaint();
+ }
+
+ public Dimension getPreferredSize() { return PREFERRED_SIZE; }
+}
diff --git a/javacore第11版/corejava/v2ch07/retire/RetireResources.java b/corejava第10版/v2ch07/retire/RetireResources.java
similarity index 100%
rename from javacore第11版/corejava/v2ch07/retire/RetireResources.java
rename to corejava第10版/v2ch07/retire/RetireResources.java
diff --git a/javacore第11版/corejava/v2ch07/retire/RetireResources_de.java b/corejava第10版/v2ch07/retire/RetireResources_de.java
similarity index 100%
rename from javacore第11版/corejava/v2ch07/retire/RetireResources_de.java
rename to corejava第10版/v2ch07/retire/RetireResources_de.java
diff --git a/javacore第11版/corejava/v2ch07/retire/RetireResources_zh.java b/corejava第10版/v2ch07/retire/RetireResources_zh.java
similarity index 100%
rename from javacore第11版/corejava/v2ch07/retire/RetireResources_zh.java
rename to corejava第10版/v2ch07/retire/RetireResources_zh.java
diff --git a/javacore第11版/corejava/v2ch07/retire/RetireStrings.properties b/corejava第10版/v2ch07/retire/RetireStrings.properties
similarity index 100%
rename from javacore第11版/corejava/v2ch07/retire/RetireStrings.properties
rename to corejava第10版/v2ch07/retire/RetireStrings.properties
diff --git a/corejava第10版/v2ch07/retire/RetireStrings_de.properties b/corejava第10版/v2ch07/retire/RetireStrings_de.properties
new file mode 100644
index 0000000..b40e50a
--- /dev/null
+++ b/corejava第10版/v2ch07/retire/RetireStrings_de.properties
@@ -0,0 +1,11 @@
+language=Sprache
+computeButton=Rechnen
+savings=Vorherige Ersparnisse
+contrib=J\u00e4hrliche Einzahlung
+income=Einkommen nach Ruhestand
+currentAge=Jetziges Alter
+retireAge=Ruhestandsalter
+deathAge=Lebenserwartung
+inflationPercent=Inflation
+investPercent=Investitionsgewinn
+retire=Alter: {0,number} Guthaben: {1,number,currency}
diff --git a/corejava第10版/v2ch07/retire/RetireStrings_zh.properties b/corejava第10版/v2ch07/retire/RetireStrings_zh.properties
new file mode 100644
index 0000000..3ffeb98
--- /dev/null
+++ b/corejava第10版/v2ch07/retire/RetireStrings_zh.properties
@@ -0,0 +1,11 @@
+language=\u8bed\u8a00
+computeButton=\u8ba1\u7b97
+savings=\u65e2\u5b58
+contrib=\u6bcf\u5e74\u5b58\u91d1
+income=\u9000\u4f11\u6536\u5165
+currentAge=\u73b0\u9f84
+retireAge=\u9000\u4f11\u5e74\u9f84
+deathAge=\u9884\u671f\u5bff\u547d
+inflationPercent=\u901a\u8d27\u81a8\u6da8
+investPercent=\u6295\u8d44\u62a5\u916c
+retire=\u5e74\u9f84: {0,number} \u603b\u7ed3: {1,number,currency}
diff --git a/javacore第11版/corejava/v2ch08/buttons1/ButtonFrame.java b/corejava第10版/v2ch08/buttons1/ButtonFrame.java
similarity index 100%
rename from javacore第11版/corejava/v2ch08/buttons1/ButtonFrame.java
rename to corejava第10版/v2ch08/buttons1/ButtonFrame.java
diff --git a/javacore第11版/corejava/v2ch08/buttons1/Renjin.properties b/corejava第10版/v2ch08/buttons1/Renjin.properties
similarity index 100%
rename from javacore第11版/corejava/v2ch08/buttons1/Renjin.properties
rename to corejava第10版/v2ch08/buttons1/Renjin.properties
diff --git a/javacore第11版/corejava/v2ch08/buttons1/groovy.properties b/corejava第10版/v2ch08/buttons1/groovy.properties
similarity index 100%
rename from javacore第11版/corejava/v2ch08/buttons1/groovy.properties
rename to corejava第10版/v2ch08/buttons1/groovy.properties
diff --git a/javacore第11版/corejava/v2ch08/buttons1/init.Renjin b/corejava第10版/v2ch08/buttons1/init.Renjin
similarity index 100%
rename from javacore第11版/corejava/v2ch08/buttons1/init.Renjin
rename to corejava第10版/v2ch08/buttons1/init.Renjin
diff --git a/javacore第11版/corejava/v2ch08/buttons1/init.sisc b/corejava第10版/v2ch08/buttons1/init.sisc
similarity index 100%
rename from javacore第11版/corejava/v2ch08/buttons1/init.sisc
rename to corejava第10版/v2ch08/buttons1/init.sisc
diff --git a/javacore第11版/corejava/v2ch08/buttons1/nashorn.properties b/corejava第10版/v2ch08/buttons1/nashorn.properties
similarity index 100%
rename from javacore第11版/corejava/v2ch08/buttons1/nashorn.properties
rename to corejava第10版/v2ch08/buttons1/nashorn.properties
diff --git a/javacore第11版/corejava/v2ch08/buttons1/sisc.properties b/corejava第10版/v2ch08/buttons1/sisc.properties
similarity index 100%
rename from javacore第11版/corejava/v2ch08/buttons1/sisc.properties
rename to corejava第10版/v2ch08/buttons1/sisc.properties
diff --git a/javacore第11版/corejava/v2ch08/buttons2/ButtonFrame.java b/corejava第10版/v2ch08/buttons2/ButtonFrame.java
similarity index 100%
rename from javacore第11版/corejava/v2ch08/buttons2/ButtonFrame.java
rename to corejava第10版/v2ch08/buttons2/ButtonFrame.java
diff --git a/javacore第11版/corejava/v2ch08/buttons2/action.properties b/corejava第10版/v2ch08/buttons2/action.properties
similarity index 100%
rename from javacore第11版/corejava/v2ch08/buttons2/action.properties
rename to corejava第10版/v2ch08/buttons2/action.properties
diff --git a/javacore第11版/corejava/v2ch08/buttons3/ButtonFrame.java b/corejava第10版/v2ch08/buttons3/ButtonFrame.java
similarity index 100%
rename from javacore第11版/corejava/v2ch08/buttons3/ButtonFrame.java
rename to corejava第10版/v2ch08/buttons3/ButtonFrame.java
diff --git a/corejava第10版/v2ch08/buttons3/ButtonTest.java b/corejava第10版/v2ch08/buttons3/ButtonTest.java
new file mode 100644
index 0000000..e015a1f
--- /dev/null
+++ b/corejava第10版/v2ch08/buttons3/ButtonTest.java
@@ -0,0 +1,23 @@
+package buttons3;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.01 2016-05-10
+ * @author Cay Horstmann
+ */
+public class ButtonTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+
+ ButtonFrame frame = new ButtonFrame();
+ frame.setTitle("ButtonTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch08/bytecodeAnnotations/EntryLogger.java b/corejava第10版/v2ch08/bytecodeAnnotations/EntryLogger.java
new file mode 100644
index 0000000..0cec47d
--- /dev/null
+++ b/corejava第10版/v2ch08/bytecodeAnnotations/EntryLogger.java
@@ -0,0 +1,86 @@
+package bytecodeAnnotations;
+
+import java.io.*;
+import java.nio.file.*;
+
+import org.objectweb.asm.*;
+import org.objectweb.asm.commons.*;
+
+/**
+ * Adds "entering" logs to all methods of a class that have the LogEntry annotation.
+ * @version 1.20 2016-05-10
+ * @author Cay Horstmann
+ */
+public class EntryLogger extends ClassVisitor
+{
+ private String className;
+
+ /**
+ * Constructs an EntryLogger that inserts logging into annotated methods of a given class.
+ * @param cg the class
+ */
+ public EntryLogger(ClassWriter writer, String className)
+ {
+ super(Opcodes.ASM5, writer);
+ this.className = className;
+ }
+
+ @Override
+ public MethodVisitor visitMethod(int access, String methodName, String desc,
+ String signature, String[] exceptions)
+ {
+ MethodVisitor mv = cv.visitMethod(access, methodName, desc, signature, exceptions);
+ return new AdviceAdapter(Opcodes.ASM5, mv, access, methodName, desc)
+ {
+ private String loggerName;
+
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible)
+ {
+ return new AnnotationVisitor(Opcodes.ASM5)
+ {
+ public void visit(String name, Object value)
+ {
+ if (desc.equals("LbytecodeAnnotations/LogEntry;") && name.equals("logger"))
+ loggerName = value.toString();
+ }
+ };
+ }
+
+ public void onMethodEnter()
+ {
+ if (loggerName != null)
+ {
+ visitLdcInsn(loggerName);
+ visitMethodInsn(INVOKESTATIC, "java/util/logging/Logger", "getLogger",
+ "(Ljava/lang/String;)Ljava/util/logging/Logger;", false);
+ visitLdcInsn(className);
+ visitLdcInsn(methodName);
+ visitMethodInsn(INVOKEVIRTUAL, "java/util/logging/Logger", "entering",
+ "(Ljava/lang/String;Ljava/lang/String;)V", false);
+ loggerName = null;
+ }
+ }
+ };
+ }
+
+ /**
+ * Adds entry logging code to the given class.
+ * @param args the name of the class file to patch
+ */
+ public static void main(String[] args) throws IOException
+ {
+ if (args.length == 0)
+ {
+ System.out.println("USAGE: java bytecodeAnnotations.EntryLogger classfile");
+ System.exit(1);
+ }
+ Path path = Paths.get(args[0]);
+ ClassReader reader = new ClassReader(Files.newInputStream(path));
+ ClassWriter writer = new ClassWriter(
+ ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
+ EntryLogger entryLogger = new EntryLogger(writer,
+ path.toString().replace(".class", "").replaceAll("[/\\\\]", "."));
+ reader.accept(entryLogger, ClassReader.EXPAND_FRAMES);
+ Files.write(Paths.get(args[0]), writer.toByteArray());
+ }
+}
diff --git a/javacore第11版/corejava/v2ch08/bytecodeAnnotations/EntryLoggingAgent.jar b/corejava第10版/v2ch08/bytecodeAnnotations/EntryLoggingAgent.jar
similarity index 100%
rename from javacore第11版/corejava/v2ch08/bytecodeAnnotations/EntryLoggingAgent.jar
rename to corejava第10版/v2ch08/bytecodeAnnotations/EntryLoggingAgent.jar
diff --git a/corejava第10版/v2ch08/bytecodeAnnotations/EntryLoggingAgent.java b/corejava第10版/v2ch08/bytecodeAnnotations/EntryLoggingAgent.java
new file mode 100644
index 0000000..d9496e1
--- /dev/null
+++ b/corejava第10版/v2ch08/bytecodeAnnotations/EntryLoggingAgent.java
@@ -0,0 +1,26 @@
+package bytecodeAnnotations;
+
+import java.lang.instrument.*;
+
+import org.objectweb.asm.*;
+
+/**
+ * @version 1.10 2016-05-10
+ * @author Cay Horstmann
+ */
+public class EntryLoggingAgent
+{
+ public static void premain(final String arg, Instrumentation instr)
+ {
+ instr.addTransformer((loader, className, cl, pd, data) ->
+ {
+ if (!className.replace("/", ".").equals(arg)) return null;
+ ClassReader reader = new ClassReader(data);
+ ClassWriter writer = new ClassWriter(
+ ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
+ EntryLogger el = new EntryLogger(writer, className);
+ reader.accept(el, ClassReader.EXPAND_FRAMES);
+ return writer.toByteArray();
+ });
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v2ch08/bytecodeAnnotations/EntryLoggingAgent.mf b/corejava第10版/v2ch08/bytecodeAnnotations/EntryLoggingAgent.mf
similarity index 100%
rename from javacore第11版/corejava/v2ch08/bytecodeAnnotations/EntryLoggingAgent.mf
rename to corejava第10版/v2ch08/bytecodeAnnotations/EntryLoggingAgent.mf
diff --git a/javacore第11版/corejava/v2ch08/bytecodeAnnotations/LogEntry.java b/corejava第10版/v2ch08/bytecodeAnnotations/LogEntry.java
similarity index 100%
rename from javacore第11版/corejava/v2ch08/bytecodeAnnotations/LogEntry.java
rename to corejava第10版/v2ch08/bytecodeAnnotations/LogEntry.java
diff --git a/corejava第10版/v2ch08/compiler/ByteArrayJavaClass.java b/corejava第10版/v2ch08/compiler/ByteArrayJavaClass.java
new file mode 100644
index 0000000..8c82735
--- /dev/null
+++ b/corejava第10版/v2ch08/compiler/ByteArrayJavaClass.java
@@ -0,0 +1,35 @@
+package compiler;
+
+import java.io.*;
+import java.net.*;
+import javax.tools.*;
+
+/**
+ * A Java class that holds the bytecodes in a byte array.
+ * @version 1.00 2007-11-02
+ * @author Cay Horstmann
+ */
+public class ByteArrayJavaClass extends SimpleJavaFileObject
+{
+ private ByteArrayOutputStream stream;
+
+ /**
+ * Constructs a new ByteArrayJavaClass.
+ * @param name the name of the class file represented by this file object
+ */
+ public ByteArrayJavaClass(String name)
+ {
+ super(URI.create("bytes:///" + name), Kind.CLASS);
+ stream = new ByteArrayOutputStream();
+ }
+
+ public OutputStream openOutputStream() throws IOException
+ {
+ return stream;
+ }
+
+ public byte[] getBytes()
+ {
+ return stream.toByteArray();
+ }
+}
diff --git a/corejava第10版/v2ch08/compiler/CompilerTest.java b/corejava第10版/v2ch08/compiler/CompilerTest.java
new file mode 100644
index 0000000..9c4d50a
--- /dev/null
+++ b/corejava第10版/v2ch08/compiler/CompilerTest.java
@@ -0,0 +1,101 @@
+package compiler;
+
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+import java.util.List;
+import javax.swing.*;
+import javax.tools.*;
+import javax.tools.JavaFileObject.*;
+
+/**
+ * @version 1.01 2016-05-10
+ * @author Cay Horstmann
+ */
+public class CompilerTest
+{
+ public static void main(final String[] args) throws IOException, ClassNotFoundException
+ {
+ JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+
+ final List classFileObjects = new ArrayList<>();
+
+ DiagnosticCollector diagnostics = new DiagnosticCollector<>();
+
+ JavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
+ fileManager = new ForwardingJavaFileManager(fileManager)
+ {
+ public JavaFileObject getJavaFileForOutput(Location location, final String className,
+ Kind kind, FileObject sibling) throws IOException
+ {
+ if (className.startsWith("x."))
+ {
+ ByteArrayJavaClass fileObject = new ByteArrayJavaClass(className);
+ classFileObjects.add(fileObject);
+ return fileObject;
+ }
+ else return super.getJavaFileForOutput(location, className, kind, sibling);
+ }
+ };
+
+
+ String frameClassName = args.length == 0 ? "buttons2.ButtonFrame" : args[0];
+ JavaFileObject source = buildSource(frameClassName);
+ JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, null,
+ null, Arrays.asList(source));
+ Boolean result = task.call();
+
+ for (Diagnostic extends JavaFileObject> d : diagnostics.getDiagnostics())
+ System.out.println(d.getKind() + ": " + d.getMessage(null));
+ fileManager.close();
+ if (!result)
+ {
+ System.out.println("Compilation failed.");
+ System.exit(1);
+ }
+
+ EventQueue.invokeLater(() ->
+ {
+ try
+ {
+ Map byteCodeMap = new HashMap<>();
+ for (ByteArrayJavaClass cl : classFileObjects)
+ byteCodeMap.put(cl.getName().substring(1), cl.getBytes());
+ ClassLoader loader = new MapClassLoader(byteCodeMap);
+ JFrame frame = (JFrame) loader.loadClass("x.Frame").newInstance();
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setTitle("CompilerTest");
+ frame.setVisible(true);
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ });
+ }
+
+ /*
+ * Builds the source for the subclass that implements the addEventHandlers method.
+ * @return a file object containing the source in a string builder
+ */
+ static JavaFileObject buildSource(String superclassName)
+ throws IOException, ClassNotFoundException
+ {
+ StringBuilderJavaSource source = new StringBuilderJavaSource("x.Frame");
+ source.append("package x;\n");
+ source.append("public class Frame extends " + superclassName + " {");
+ source.append("protected void addEventHandlers() {");
+ final Properties props = new Properties();
+ props.load(Class.forName(superclassName).getResourceAsStream("action.properties"));
+ for (Map.Entry e : props.entrySet())
+ {
+ String beanName = (String) e.getKey();
+ String eventCode = (String) e.getValue();
+ source.append(beanName + ".addActionListener(event -> {");
+ source.append(eventCode);
+ source.append("} );");
+ }
+ source.append("} }");
+ return source;
+ }
+}
diff --git a/corejava第10版/v2ch08/compiler/MapClassLoader.java b/corejava第10版/v2ch08/compiler/MapClassLoader.java
new file mode 100644
index 0000000..c597824
--- /dev/null
+++ b/corejava第10版/v2ch08/compiler/MapClassLoader.java
@@ -0,0 +1,28 @@
+package compiler;
+
+import java.util.*;
+
+/**
+ * A class loader that loads classes from a map whose keys are class names and whose values are byte
+ * code arrays.
+ * @version 1.00 2007-11-02
+ * @author Cay Horstmann
+ */
+public class MapClassLoader extends ClassLoader
+{
+ private Map classes;
+
+ public MapClassLoader(Map classes)
+ {
+ this.classes = classes;
+ }
+
+ protected Class> findClass(String name) throws ClassNotFoundException
+ {
+ byte[] classBytes = classes.get(name);
+ if (classBytes == null) throw new ClassNotFoundException(name);
+ Class> cl = defineClass(name, classBytes, 0, classBytes.length);
+ if (cl == null) throw new ClassNotFoundException(name);
+ return cl;
+ }
+}
diff --git a/corejava第10版/v2ch08/compiler/StringBuilderJavaSource.java b/corejava第10版/v2ch08/compiler/StringBuilderJavaSource.java
new file mode 100644
index 0000000..0fc8deb
--- /dev/null
+++ b/corejava第10版/v2ch08/compiler/StringBuilderJavaSource.java
@@ -0,0 +1,36 @@
+package compiler;
+
+import java.net.*;
+import javax.tools.*;
+
+/**
+ * A Java source that holds the code in a string builder.
+ * @version 1.00 2007-11-02
+ * @author Cay Horstmann
+ */
+public class StringBuilderJavaSource extends SimpleJavaFileObject
+{
+ private StringBuilder code;
+
+ /**
+ * Constructs a new StringBuilderJavaSource.
+ * @param name the name of the source file represented by this file object
+ */
+ public StringBuilderJavaSource(String name)
+ {
+ super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension),
+ Kind.SOURCE);
+ code = new StringBuilder();
+ }
+
+ public CharSequence getCharContent(boolean ignoreEncodingErrors)
+ {
+ return code;
+ }
+
+ public void append(String str)
+ {
+ code.append(str);
+ code.append('\n');
+ }
+}
diff --git a/corejava第10版/v2ch08/rect/Point.java b/corejava第10版/v2ch08/rect/Point.java
new file mode 100644
index 0000000..e716cfb
--- /dev/null
+++ b/corejava第10版/v2ch08/rect/Point.java
@@ -0,0 +1,15 @@
+package rect;
+
+import sourceAnnotations.ToString;
+
+@ToString(includeName=false)
+public class Point {
+ private int x;
+ private int y;
+ public Point(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+ @ToString(includeName=false) public int getX() { return x; }
+ @ToString(includeName=false) public int getY() { return y; }
+}
diff --git a/corejava第10版/v2ch08/rect/Rectangle.java b/corejava第10版/v2ch08/rect/Rectangle.java
new file mode 100644
index 0000000..2e78fc0
--- /dev/null
+++ b/corejava第10版/v2ch08/rect/Rectangle.java
@@ -0,0 +1,18 @@
+package rect;
+
+import sourceAnnotations.ToString;
+
+@ToString
+public class Rectangle {
+ private Point topLeft;
+ private int width;
+ private int height;
+ public Rectangle(Point topLeft, int width, int height) {
+ this.topLeft = topLeft;
+ this.width = width;
+ this.height = height;
+ }
+ @ToString(includeName=false) public Point getTopLeft() { return topLeft; }
+ @ToString public int getWidth() { return width; }
+ @ToString public int getHeight() { return height; }
+}
diff --git a/corejava第10版/v2ch08/rect/SourceLevelAnnotationDemo.java b/corejava第10版/v2ch08/rect/SourceLevelAnnotationDemo.java
new file mode 100644
index 0000000..e0b0427
--- /dev/null
+++ b/corejava第10版/v2ch08/rect/SourceLevelAnnotationDemo.java
@@ -0,0 +1,12 @@
+package rect;
+
+import sourceAnnotations.ToStrings;
+
+public class SourceLevelAnnotationDemo
+{
+ public static void main(String[] args)
+ {
+ Rectangle rect = new Rectangle(new Point(10, 10), 20, 30);
+ System.out.println(ToStrings.toString(rect));
+ }
+}
diff --git a/corejava第10版/v2ch08/runtimeAnnotations/ActionListenerFor.java b/corejava第10版/v2ch08/runtimeAnnotations/ActionListenerFor.java
new file mode 100644
index 0000000..54bba9e
--- /dev/null
+++ b/corejava第10版/v2ch08/runtimeAnnotations/ActionListenerFor.java
@@ -0,0 +1,15 @@
+package runtimeAnnotations;
+
+import java.lang.annotation.*;
+
+/**
+ * @version 1.00 2004-08-17
+ * @author Cay Horstmann
+ */
+
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ActionListenerFor
+{
+ String source();
+}
diff --git a/corejava第10版/v2ch08/runtimeAnnotations/ActionListenerInstaller.java b/corejava第10版/v2ch08/runtimeAnnotations/ActionListenerInstaller.java
new file mode 100644
index 0000000..028e27d
--- /dev/null
+++ b/corejava第10版/v2ch08/runtimeAnnotations/ActionListenerInstaller.java
@@ -0,0 +1,60 @@
+package runtimeAnnotations;
+
+import java.awt.event.*;
+import java.lang.reflect.*;
+
+/**
+ * @version 1.00 2004-08-17
+ * @author Cay Horstmann
+ */
+public class ActionListenerInstaller
+{
+ /**
+ * Processes all ActionListenerFor annotations in the given object.
+ * @param obj an object whose methods may have ActionListenerFor annotations
+ */
+ public static void processAnnotations(Object obj)
+ {
+ try
+ {
+ Class> cl = obj.getClass();
+ for (Method m : cl.getDeclaredMethods())
+ {
+ ActionListenerFor a = m.getAnnotation(ActionListenerFor.class);
+ if (a != null)
+ {
+ Field f = cl.getDeclaredField(a.source());
+ f.setAccessible(true);
+ addListener(f.get(obj), obj, m);
+ }
+ }
+ }
+ catch (ReflectiveOperationException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Adds an action listener that calls a given method.
+ * @param source the event source to which an action listener is added
+ * @param param the implicit parameter of the method that the listener calls
+ * @param m the method that the listener calls
+ */
+ public static void addListener(Object source, final Object param, final Method m)
+ throws ReflectiveOperationException
+ {
+ InvocationHandler handler = new InvocationHandler()
+ {
+ public Object invoke(Object proxy, Method mm, Object[] args) throws Throwable
+ {
+ return m.invoke(param);
+ }
+ };
+
+ Object listener = Proxy.newProxyInstance(null,
+ new Class[] { java.awt.event.ActionListener.class }, handler);
+ Method adder = source.getClass().getMethod("addActionListener", ActionListener.class);
+ adder.invoke(source, listener);
+ }
+}
diff --git a/corejava第10版/v2ch08/script/ScriptTest.java b/corejava第10版/v2ch08/script/ScriptTest.java
new file mode 100644
index 0000000..7a246c3
--- /dev/null
+++ b/corejava第10版/v2ch08/script/ScriptTest.java
@@ -0,0 +1,122 @@
+package script;
+
+import java.awt.*;
+import java.beans.*;
+import java.io.*;
+import java.lang.reflect.*;
+import java.util.*;
+import javax.script.*;
+import javax.swing.*;
+
+/**
+ * @version 1.02 2016-05-10
+ * @author Cay Horstmann
+ */
+public class ScriptTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ try
+ {
+ ScriptEngineManager manager = new ScriptEngineManager();
+ String language;
+ if (args.length == 0)
+ {
+ System.out.println("Available factories: ");
+ for (ScriptEngineFactory factory : manager.getEngineFactories())
+ System.out.println(factory.getEngineName());
+
+ language = "nashorn";
+ }
+ else language = args[0];
+
+ final ScriptEngine engine = manager.getEngineByName(language);
+ if (engine == null)
+ {
+ System.err.println("No engine for " + language);
+ System.exit(1);
+ }
+
+ final String frameClassName = args.length < 2 ? "buttons1.ButtonFrame" : args[1];
+
+ JFrame frame = (JFrame) Class.forName(frameClassName).newInstance();
+ InputStream in = frame.getClass().getResourceAsStream("init." + language);
+ if (in != null) engine.eval(new InputStreamReader(in));
+ Map components = new HashMap<>();
+ getComponentBindings(frame, components);
+ components.forEach((name, c) -> engine.put(name, c));
+
+ final Properties events = new Properties();
+ in = frame.getClass().getResourceAsStream(language + ".properties");
+ events.load(in);
+
+ for (final Object e : events.keySet())
+ {
+ String[] s = ((String) e).split("\\.");
+ addListener(s[0], s[1], (String) events.get(e), engine, components);
+ }
+ frame.setTitle("ScriptTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ }
+ catch (ReflectiveOperationException | IOException
+ | ScriptException | IntrospectionException ex)
+ {
+ ex.printStackTrace();
+ }
+ });
+ }
+
+ /**
+ * Gathers all named components in a container.
+ * @param c the component
+ * @param namedComponents a map into which to enter the component names and components
+ */
+ private static void getComponentBindings(Component c, Map namedComponents)
+ {
+ String name = c.getName();
+ if (name != null) { namedComponents.put(name, c); }
+ if (c instanceof Container)
+ {
+ for (Component child : ((Container) c).getComponents())
+ getComponentBindings(child, namedComponents);
+ }
+ }
+
+ /**
+ * Adds a listener to an object whose listener method executes a script.
+ * @param beanName the name of the bean to which the listener should be added
+ * @param eventName the name of the listener type, such as "action" or "change"
+ * @param scriptCode the script code to be executed
+ * @param engine the engine that executes the code
+ * @param bindings the bindings for the execution
+ * @throws IntrospectionException
+ */
+ private static void addListener(String beanName, String eventName, final String scriptCode,
+ final ScriptEngine engine, Map components)
+ throws ReflectiveOperationException, IntrospectionException
+ {
+ Object bean = components.get(beanName);
+ EventSetDescriptor descriptor = getEventSetDescriptor(bean, eventName);
+ if (descriptor == null) return;
+ descriptor.getAddListenerMethod().invoke(bean,
+ Proxy.newProxyInstance(null, new Class[] { descriptor.getListenerType() },
+ (proxy, method, args) ->
+ {
+ engine.eval(scriptCode);
+ return null;
+ }
+ ));
+ }
+
+ private static EventSetDescriptor getEventSetDescriptor(Object bean, String eventName)
+ throws IntrospectionException
+ {
+ for (EventSetDescriptor descriptor : Introspector.getBeanInfo(bean.getClass())
+ .getEventSetDescriptors())
+ if (descriptor.getName().equals(eventName)) return descriptor;
+ return null;
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch08/set/Item.java b/corejava第10版/v2ch08/set/Item.java
new file mode 100644
index 0000000..93c32a2
--- /dev/null
+++ b/corejava第10版/v2ch08/set/Item.java
@@ -0,0 +1,56 @@
+package set;
+
+import java.util.*;
+import bytecodeAnnotations.*;
+
+/**
+ * An item with a description and a part number.
+ * @version 1.01 2012-01-26
+ * @author Cay Horstmann
+ */
+public class Item
+{
+ private String description;
+ private int partNumber;
+
+ /**
+ * 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 "[description=" + description + ", partNumber=" + partNumber + "]";
+ }
+
+ @LogEntry(logger = "com.horstmann")
+ 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 Objects.equals(description, other.description) && partNumber == other.partNumber;
+ }
+
+ @LogEntry(logger = "com.horstmann")
+ public int hashCode()
+ {
+ return Objects.hash(description, partNumber);
+ }
+}
diff --git a/corejava第10版/v2ch08/set/SetTest.java b/corejava第10版/v2ch08/set/SetTest.java
new file mode 100644
index 0000000..12e1901
--- /dev/null
+++ b/corejava第10版/v2ch08/set/SetTest.java
@@ -0,0 +1,25 @@
+package set;
+
+import java.util.*;
+import java.util.logging.*;
+
+/**
+ * @version 1.02 2012-01-26
+ * @author Cay Horstmann
+ */
+public class SetTest
+{
+ public static void main(String[] args)
+ {
+ Logger.getLogger("com.horstmann").setLevel(Level.FINEST);
+ Handler handler = new ConsoleHandler();
+ handler.setLevel(Level.FINEST);
+ Logger.getLogger("com.horstmann").addHandler(handler);
+
+ Set- parts = new HashSet<>();
+ parts.add(new Item("Toaster", 1279));
+ parts.add(new Item("Microwave", 4104));
+ parts.add(new Item("Toaster", 1279));
+ System.out.println(parts);
+ }
+}
diff --git a/corejava第10版/v2ch08/sourceAnnotations/ToString.java b/corejava第10版/v2ch08/sourceAnnotations/ToString.java
new file mode 100644
index 0000000..074dc67
--- /dev/null
+++ b/corejava第10版/v2ch08/sourceAnnotations/ToString.java
@@ -0,0 +1,12 @@
+package sourceAnnotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.SOURCE)
+public @interface ToString {
+ boolean includeName() default true;
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch08/sourceAnnotations/ToStringAnnotationProcessor.java b/corejava第10版/v2ch08/sourceAnnotations/ToStringAnnotationProcessor.java
new file mode 100644
index 0000000..01d0372
--- /dev/null
+++ b/corejava第10版/v2ch08/sourceAnnotations/ToStringAnnotationProcessor.java
@@ -0,0 +1,79 @@
+package sourceAnnotations;
+
+import java.beans.*;
+import java.io.*;
+import java.util.*;
+
+import javax.annotation.processing.*;
+import javax.lang.model.*;
+import javax.lang.model.element.*;
+import javax.tools.*;
+import javax.tools.Diagnostic.Kind;
+
+@SupportedAnnotationTypes("sourceAnnotations.ToString")
+@SupportedSourceVersion(SourceVersion.RELEASE_8)
+public class ToStringAnnotationProcessor extends AbstractProcessor
+{
+ @Override
+ public boolean process(Set extends TypeElement> annotations,
+ RoundEnvironment currentRound)
+ {
+ if (annotations.size() == 0) return true;
+ try
+ {
+ JavaFileObject sourceFile = processingEnv.getFiler().createSourceFile("sourceAnnotations.ToStrings");
+ try (PrintWriter out = new PrintWriter(sourceFile.openWriter())) {
+ out.println("// Automatically generated by sourceAnnotations.ToStringAnnotationProcessor");
+ out.println("package sourceAnnotations;");
+ out.println("public class ToStrings {");
+
+ for (Element e : currentRound.getElementsAnnotatedWith(ToString.class)) {
+ if (e instanceof TypeElement)
+ {
+ TypeElement te = (TypeElement) e;
+ writeToStringMethod(out, te);
+ }
+ }
+ out.println(" public static String toString(Object obj) {");
+ out.println(" return java.util.Objects.toString(obj);");
+ out.println(" }");
+ out.println("}");
+ }
+ }
+ catch (IOException ex)
+ {
+ processingEnv.getMessager().printMessage(Kind.ERROR, ex.getMessage());
+ }
+ return true;
+ }
+
+ private void writeToStringMethod(PrintWriter out, TypeElement te)
+ {
+ String className = te.getQualifiedName().toString();
+ out.println(" public static String toString(" + className + " obj) {");
+ ToString ann = te.getAnnotation(ToString.class);
+ out.println(" StringBuilder result = new StringBuilder();");
+ if (ann.includeName()) out.println(" result.append(\"" + className + "\");");
+ out.println(" result.append(\"[\");");
+ boolean first = true;
+ for (Element c : te.getEnclosedElements())
+ {
+ String methodName = c.getSimpleName().toString();
+ ann = c.getAnnotation(ToString.class);
+ if (ann != null)
+ {
+ if (first) first = false; else out.println(" result.append(\",\");");
+ if (ann.includeName())
+ {
+ String fieldName = Introspector.decapitalize(methodName.replaceAll("^(get|is)", ""));
+ // Turn getWidth into width, isDone into done, getURL into URL
+ out.println(" result.append(\"" + fieldName + "=" + "\");");
+ }
+ out.println(" result.append(toString(obj." + methodName + "()));");
+ }
+ }
+ out.println(" result.append(\"]\");");
+ out.println(" return result.toString();");
+ out.println(" }");
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch08/sourceAnnotations/ToStrings.java b/corejava第10版/v2ch08/sourceAnnotations/ToStrings.java
new file mode 100644
index 0000000..3b42a4d
--- /dev/null
+++ b/corejava第10版/v2ch08/sourceAnnotations/ToStrings.java
@@ -0,0 +1,30 @@
+// Automatically generated by sourceAnnotations.ToStringAnnotationProcessor
+package sourceAnnotations;
+public class ToStrings {
+ public static String toString(rect.Point obj) {
+ StringBuilder result = new StringBuilder();
+ result.append("[");
+ result.append(toString(obj.getX()));
+ result.append(",");
+ result.append(toString(obj.getY()));
+ result.append("]");
+ return result.toString();
+ }
+ public static String toString(rect.Rectangle obj) {
+ StringBuilder result = new StringBuilder();
+ result.append("rect.Rectangle");
+ result.append("[");
+ result.append(toString(obj.getTopLeft()));
+ result.append(",");
+ result.append("width=");
+ result.append(toString(obj.getWidth()));
+ result.append(",");
+ result.append("height=");
+ result.append(toString(obj.getHeight()));
+ result.append("]");
+ return result.toString();
+ }
+ public static String toString(Object obj) {
+ return java.util.Objects.toString(obj);
+ }
+}
diff --git a/javacore第11版/corejava/v2ch10/Calculator.caesar b/corejava第10版/v2ch09/Calculator.caesar
similarity index 100%
rename from javacore第11版/corejava/v2ch10/Calculator.caesar
rename to corejava第10版/v2ch09/Calculator.caesar
diff --git a/javacore第11版/corejava/v2ch10/CalculatorFrame.caesar b/corejava第10版/v2ch09/CalculatorFrame.caesar
similarity index 100%
rename from javacore第11版/corejava/v2ch10/CalculatorFrame.caesar
rename to corejava第10版/v2ch09/CalculatorFrame.caesar
diff --git a/javacore第11版/corejava/v2ch10/CalculatorPanel$1.caesar b/corejava第10版/v2ch09/CalculatorPanel$1.caesar
similarity index 100%
rename from javacore第11版/corejava/v2ch10/CalculatorPanel$1.caesar
rename to corejava第10版/v2ch09/CalculatorPanel$1.caesar
diff --git a/javacore第11版/corejava/v2ch10/CalculatorPanel$CommandAction.caesar b/corejava第10版/v2ch09/CalculatorPanel$CommandAction.caesar
similarity index 100%
rename from javacore第11版/corejava/v2ch10/CalculatorPanel$CommandAction.caesar
rename to corejava第10版/v2ch09/CalculatorPanel$CommandAction.caesar
diff --git a/javacore第11版/corejava/v2ch10/CalculatorPanel$InsertAction.caesar b/corejava第10版/v2ch09/CalculatorPanel$InsertAction.caesar
similarity index 100%
rename from javacore第11版/corejava/v2ch10/CalculatorPanel$InsertAction.caesar
rename to corejava第10版/v2ch09/CalculatorPanel$InsertAction.caesar
diff --git a/javacore第11版/corejava/v2ch10/CalculatorPanel.caesar b/corejava第10版/v2ch09/CalculatorPanel.caesar
similarity index 100%
rename from javacore第11版/corejava/v2ch10/CalculatorPanel.caesar
rename to corejava第10版/v2ch09/CalculatorPanel.caesar
diff --git a/corejava第10版/v2ch09/FileReadApplet.html b/corejava第10版/v2ch09/FileReadApplet.html
new file mode 100644
index 0000000..1642dcc
--- /dev/null
+++ b/corejava第10版/v2ch09/FileReadApplet.html
@@ -0,0 +1,3 @@
+
+
diff --git a/corejava第10版/v2ch09/aes/AESTest.java b/corejava第10版/v2ch09/aes/AESTest.java
new file mode 100644
index 0000000..bd9019b
--- /dev/null
+++ b/corejava第10版/v2ch09/aes/AESTest.java
@@ -0,0 +1,49 @@
+package aes;
+
+import java.io.*;
+import java.security.*;
+import javax.crypto.*;
+
+/**
+ * This program tests the AES cipher. Usage:
+ * java aes.AESTest -genkey keyfile
+ * java aes.AESTest -encrypt plaintext encrypted keyfile
+ * java aes.AESTest -decrypt encrypted decrypted keyfile
+ * @author Cay Horstmann
+ * @version 1.01 2012-06-10
+ */
+public class AESTest
+{
+ public static void main(String[] args)
+ throws IOException, GeneralSecurityException, ClassNotFoundException
+ {
+ if (args[0].equals("-genkey"))
+ {
+ KeyGenerator keygen = KeyGenerator.getInstance("AES");
+ SecureRandom random = new SecureRandom();
+ keygen.init(random);
+ SecretKey key = keygen.generateKey();
+ try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(args[1])))
+ {
+ out.writeObject(key);
+ }
+ }
+ else
+ {
+ int mode;
+ if (args[0].equals("-encrypt")) mode = Cipher.ENCRYPT_MODE;
+ else mode = Cipher.DECRYPT_MODE;
+
+ try (ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(args[3]));
+ InputStream in = new FileInputStream(args[1]);
+ OutputStream out = new FileOutputStream(args[2]))
+ {
+ Key key = (Key) keyIn.readObject();
+ Cipher cipher = Cipher.getInstance("AES");
+ cipher.init(mode, key);
+ Util.crypt(in, out, cipher);
+ }
+ }
+ }
+}
+
diff --git a/corejava第10版/v2ch09/aes/Util.java b/corejava第10版/v2ch09/aes/Util.java
new file mode 100644
index 0000000..369e3b0
--- /dev/null
+++ b/corejava第10版/v2ch09/aes/Util.java
@@ -0,0 +1,40 @@
+package aes;
+
+import java.io.*;
+import java.security.*;
+import javax.crypto.*;
+
+public class Util
+{
+ /**
+ * Uses a cipher to transform the bytes in an input stream and sends the transformed bytes to an
+ * output stream.
+ * @param in the input stream
+ * @param out the output stream
+ * @param cipher the cipher that transforms the bytes
+ */
+ public static void crypt(InputStream in, OutputStream out, Cipher cipher) throws IOException,
+ GeneralSecurityException
+ {
+ int blockSize = cipher.getBlockSize();
+ int outputSize = cipher.getOutputSize(blockSize);
+ byte[] inBytes = new byte[blockSize];
+ byte[] outBytes = new byte[outputSize];
+
+ int inLength = 0;
+ boolean more = true;
+ while (more)
+ {
+ inLength = in.read(inBytes);
+ if (inLength == blockSize)
+ {
+ int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
+ out.write(outBytes, 0, outLength);
+ }
+ else more = false;
+ }
+ if (inLength > 0) outBytes = cipher.doFinal(inBytes, 0, inLength);
+ else outBytes = cipher.doFinal();
+ out.write(outBytes);
+ }
+}
diff --git a/corejava第10版/v2ch09/applet.policy b/corejava第10版/v2ch09/applet.policy
new file mode 100644
index 0000000..e89adeb
--- /dev/null
+++ b/corejava第10版/v2ch09/applet.policy
@@ -0,0 +1,7 @@
+keystore "client.certs", "JKS";
+
+grant signedby "acmeroot"
+{
+ permission java.lang.RuntimePermission "usePolicy";
+ permission java.io.FilePermission "/etc/*", "read";
+};
diff --git a/corejava第10版/v2ch09/auth/AuthTest.java b/corejava第10版/v2ch09/auth/AuthTest.java
new file mode 100644
index 0000000..c112cb8
--- /dev/null
+++ b/corejava第10版/v2ch09/auth/AuthTest.java
@@ -0,0 +1,35 @@
+package auth;
+
+import java.security.*;
+import javax.security.auth.*;
+import javax.security.auth.login.*;
+
+/**
+ * This program authenticates a user via a custom login and then executes the SysPropAction with the
+ * user's privileges.
+ * @version 1.01 2007-10-06
+ * @author Cay Horstmann
+ */
+public class AuthTest
+{
+ public static void main(final String[] args)
+ {
+ System.setSecurityManager(new SecurityManager());
+ try
+ {
+ LoginContext context = new LoginContext("Login1");
+ context.login();
+ System.out.println("Authentication successful.");
+ Subject subject = context.getSubject();
+ System.out.println("subject=" + subject);
+ PrivilegedAction action = new SysPropAction("user.home");
+ String result = Subject.doAsPrivileged(subject, action, null);
+ System.out.println(result);
+ context.logout();
+ }
+ catch (LoginException e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/javacore第11版/corejava/v2ch10/auth/AuthTest.policy b/corejava第10版/v2ch09/auth/AuthTest.policy
similarity index 100%
rename from javacore第11版/corejava/v2ch10/auth/AuthTest.policy
rename to corejava第10版/v2ch09/auth/AuthTest.policy
diff --git a/corejava第10版/v2ch09/auth/SysPropAction.java b/corejava第10版/v2ch09/auth/SysPropAction.java
new file mode 100644
index 0000000..72707a2
--- /dev/null
+++ b/corejava第10版/v2ch09/auth/SysPropAction.java
@@ -0,0 +1,24 @@
+package auth;
+
+import java.security.*;
+
+/**
+ This action looks up a system property.
+ * @version 1.01 2007-10-06
+ * @author Cay Horstmann
+*/
+public class SysPropAction implements PrivilegedAction
+{
+ private String propertyName;
+
+ /**
+ Constructs an action for looking up a given property.
+ @param propertyName the property name (such as "user.home")
+ */
+ public SysPropAction(String propertyName) { this.propertyName = propertyName; }
+
+ public String run()
+ {
+ return System.getProperty(propertyName);
+ }
+}
diff --git a/javacore第11版/corejava/v2ch10/auth/action.jar b/corejava第10版/v2ch09/auth/action.jar
similarity index 100%
rename from javacore第11版/corejava/v2ch10/auth/action.jar
rename to corejava第10版/v2ch09/auth/action.jar
diff --git a/javacore第11版/corejava/v2ch10/auth/jaas.config b/corejava第10版/v2ch09/auth/jaas.config
similarity index 100%
rename from javacore第11版/corejava/v2ch10/auth/jaas.config
rename to corejava第10版/v2ch09/auth/jaas.config
diff --git a/javacore第11版/corejava/v2ch10/auth/login.jar b/corejava第10版/v2ch09/auth/login.jar
similarity index 100%
rename from javacore第11版/corejava/v2ch10/auth/login.jar
rename to corejava第10版/v2ch09/auth/login.jar
diff --git a/corejava第10版/v2ch09/classLoader/Caesar.java b/corejava第10版/v2ch09/classLoader/Caesar.java
new file mode 100644
index 0000000..d9a0b9d
--- /dev/null
+++ b/corejava第10版/v2ch09/classLoader/Caesar.java
@@ -0,0 +1,32 @@
+package classLoader;
+
+import java.io.*;
+
+/**
+ * Encrypts a file using the Caesar cipher.
+ * @version 1.01 2012-06-10
+ * @author Cay Horstmann
+ */
+public class Caesar
+{
+ public static void main(String[] args) throws Exception
+ {
+ if (args.length != 3)
+ {
+ System.out.println("USAGE: java classLoader.Caesar in out key");
+ return;
+ }
+
+ try(FileInputStream in = new FileInputStream(args[0]);
+ FileOutputStream out = new FileOutputStream(args[1]))
+ {
+ int key = Integer.parseInt(args[2]);
+ int ch;
+ while ((ch = in.read()) != -1)
+ {
+ byte c = (byte) (ch + key);
+ out.write(c);
+ }
+ }
+ }
+}
diff --git a/corejava第10版/v2ch09/classLoader/ClassLoaderTest.java b/corejava第10版/v2ch09/classLoader/ClassLoaderTest.java
new file mode 100644
index 0000000..9aa0abb
--- /dev/null
+++ b/corejava第10版/v2ch09/classLoader/ClassLoaderTest.java
@@ -0,0 +1,120 @@
+package classLoader;
+
+import java.io.*;
+import java.lang.reflect.*;
+import java.nio.file.*;
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates a custom class loader that decrypts class files.
+ * @version 1.24 2016-05-10
+ * @author Cay Horstmann
+ */
+public class ClassLoaderTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new ClassLoaderFrame();
+ frame.setTitle("ClassLoaderTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * This frame contains two text fields for the name of the class to load and the decryption key.
+ */
+class ClassLoaderFrame extends JFrame
+{
+ private JTextField keyField = new JTextField("3", 4);
+ private JTextField nameField = new JTextField("Calculator", 30);
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 200;
+
+ public ClassLoaderFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+ setLayout(new GridBagLayout());
+ add(new JLabel("Class"), new GBC(0, 0).setAnchor(GBC.EAST));
+ add(nameField, new GBC(1, 0).setWeight(100, 0).setAnchor(GBC.WEST));
+ add(new JLabel("Key"), new GBC(0, 1).setAnchor(GBC.EAST));
+ add(keyField, new GBC(1, 1).setWeight(100, 0).setAnchor(GBC.WEST));
+ JButton loadButton = new JButton("Load");
+ add(loadButton, new GBC(0, 2, 2, 1));
+ loadButton.addActionListener(event -> runClass(nameField.getText(), keyField.getText()));
+ pack();
+ }
+
+ /**
+ * Runs the main method of a given class.
+ * @param name the class name
+ * @param key the decryption key for the class files
+ */
+ public void runClass(String name, String key)
+ {
+ try
+ {
+ ClassLoader loader = new CryptoClassLoader(Integer.parseInt(key));
+ Class> c = loader.loadClass(name);
+ Method m = c.getMethod("main", String[].class);
+ m.invoke(null, (Object) new String[] {});
+ }
+ catch (Throwable e)
+ {
+ JOptionPane.showMessageDialog(this, e);
+ }
+ }
+
+}
+
+/**
+ * This class loader loads encrypted class files.
+ */
+class CryptoClassLoader extends ClassLoader
+{
+ private int key;
+
+ /**
+ * Constructs a crypto class loader.
+ * @param k the decryption key
+ */
+ public CryptoClassLoader(int k)
+ {
+ key = k;
+ }
+
+ protected Class> findClass(String name) throws ClassNotFoundException
+ {
+ try
+ {
+ byte[] classBytes = null;
+ classBytes = loadClassBytes(name);
+ Class> cl = defineClass(name, classBytes, 0, classBytes.length);
+ if (cl == null) throw new ClassNotFoundException(name);
+ return cl;
+ }
+ catch (IOException e)
+ {
+ throw new ClassNotFoundException(name);
+ }
+ }
+
+ /**
+ * Loads and decrypt the class file bytes.
+ * @param name the class name
+ * @return an array with the class file bytes
+ */
+ private byte[] loadClassBytes(String name) throws IOException
+ {
+ String cname = name.replace('.', '/') + ".caesar";
+ byte[] bytes = Files.readAllBytes(Paths.get(cname));
+ for (int i = 0; i < bytes.length; i++)
+ bytes[i] = (byte) (bytes[i] - key);
+ return bytes;
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v2ch10/classLoader/GBC.java b/corejava第10版/v2ch09/classLoader/GBC.java
similarity index 100%
rename from javacore第11版/corejava/v2ch10/classLoader/GBC.java
rename to corejava第10版/v2ch09/classLoader/GBC.java
diff --git a/corejava第10版/v2ch09/hash/Digest.java b/corejava第10版/v2ch09/hash/Digest.java
new file mode 100644
index 0000000..966cb56
--- /dev/null
+++ b/corejava第10版/v2ch09/hash/Digest.java
@@ -0,0 +1,33 @@
+package hash;
+
+import java.io.*;
+import java.nio.file.*;
+import java.security.*;
+
+/**
+ * This program computes the message digest of a file.
+ * @version 1.20 2012-06-16
+ * @author Cay Horstmann
+ */
+public class Digest
+{
+ /**
+ * @param args args[0] is the filename, args[1] is optionally the algorithm
+ * (SHA-1, SHA-256, or MD5)
+ */
+ public static void main(String[] args) throws IOException, GeneralSecurityException
+ {
+ String algname = args.length >= 2 ? args[1] : "SHA-1";
+ MessageDigest alg = MessageDigest.getInstance(algname);
+ byte[] input = Files.readAllBytes(Paths.get(args[0]));
+ byte[] hash = alg.digest(input);
+ String d = "";
+ for (int i = 0; i < hash.length; i++)
+ {
+ int v = hash[i] & 0xFF;
+ if (v < 16) d += "0";
+ d += Integer.toString(v, 16).toUpperCase() + " ";
+ }
+ System.out.println(d);
+ }
+}
diff --git a/javacore第11版/corejava/v2ch10/hash/input.txt b/corejava第10版/v2ch09/hash/input.txt
similarity index 100%
rename from javacore第11版/corejava/v2ch10/hash/input.txt
rename to corejava第10版/v2ch09/hash/input.txt
diff --git a/corejava第10版/v2ch09/jaas/JAASFrame.java b/corejava第10版/v2ch09/jaas/JAASFrame.java
new file mode 100644
index 0000000..a636b34
--- /dev/null
+++ b/corejava第10版/v2ch09/jaas/JAASFrame.java
@@ -0,0 +1,67 @@
+package jaas;
+
+import java.awt.*;
+
+import javax.security.auth.*;
+import javax.security.auth.login.*;
+import javax.swing.*;
+
+/**
+ * This frame has text fields for user name and password, a field for the name of the requested
+ * system property, and a field to show the property value.
+ */
+public class JAASFrame extends JFrame
+{
+ private JTextField username;
+ private JPasswordField password;
+ private JTextField propertyName;
+ private JTextField propertyValue;
+
+ public JAASFrame()
+ {
+ username = new JTextField(20);
+ password = new JPasswordField(20);
+ propertyName = new JTextField("user.home");
+ propertyValue = new JTextField(20);
+ propertyValue.setEditable(false);
+
+ JPanel panel = new JPanel();
+ panel.setLayout(new GridLayout(0, 2));
+ panel.add(new JLabel("username:"));
+ panel.add(username);
+ panel.add(new JLabel("password:"));
+ panel.add(password);
+ panel.add(propertyName);
+ panel.add(propertyValue);
+ add(panel, BorderLayout.CENTER);
+
+ JButton getValueButton = new JButton("Get Value");
+ getValueButton.addActionListener(event -> getValue());
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.add(getValueButton);
+ add(buttonPanel, BorderLayout.SOUTH);
+ pack();
+ }
+
+ public void getValue()
+ {
+ try
+ {
+ LoginContext context = new LoginContext("Login1", new SimpleCallbackHandler(
+ username.getText(), password.getPassword()));
+ System.out.println("Trying to log in with " + username.getText()
+ + " and " + new String(password.getPassword()));
+ context.login();
+ Subject subject = context.getSubject();
+ propertyValue.setText(""
+ + Subject.doAsPrivileged(subject, new SysPropAction(propertyName.getText()), null));
+ context.logout();
+ }
+ catch (LoginException ex)
+ {
+ ex.printStackTrace();
+ Throwable ex2 = ex.getCause();
+ if (ex2 != null) ex2.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch09/jaas/JAASTest.java b/corejava第10版/v2ch09/jaas/JAASTest.java
new file mode 100644
index 0000000..ae9d98b
--- /dev/null
+++ b/corejava第10版/v2ch09/jaas/JAASTest.java
@@ -0,0 +1,25 @@
+package jaas;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program authenticates a user via a custom login and then looks up a system property with the
+ * user's privileges.
+ * @version 1.02 2016-05-10
+ * @author Cay Horstmann
+ */
+public class JAASTest
+{
+ public static void main(final String[] args)
+ {
+ System.setSecurityManager(new SecurityManager());
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new JAASFrame();
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setTitle("JAASTest");
+ frame.setVisible(true);
+ });
+ }
+}
diff --git a/javacore第11版/corejava/v2ch10/jaas/JAASTest.policy b/corejava第10版/v2ch09/jaas/JAASTest.policy
similarity index 100%
rename from javacore第11版/corejava/v2ch10/jaas/JAASTest.policy
rename to corejava第10版/v2ch09/jaas/JAASTest.policy
diff --git a/javacore第11版/corejava/v2ch10/jaas/SimpleCallbackHandler.java b/corejava第10版/v2ch09/jaas/SimpleCallbackHandler.java
similarity index 100%
rename from javacore第11版/corejava/v2ch10/jaas/SimpleCallbackHandler.java
rename to corejava第10版/v2ch09/jaas/SimpleCallbackHandler.java
diff --git a/corejava第10版/v2ch09/jaas/SimpleLoginModule.java b/corejava第10版/v2ch09/jaas/SimpleLoginModule.java
new file mode 100644
index 0000000..85673a3
--- /dev/null
+++ b/corejava第10版/v2ch09/jaas/SimpleLoginModule.java
@@ -0,0 +1,106 @@
+package jaas;
+
+import java.io.*;
+import java.nio.file.*;
+import java.security.*;
+import java.util.*;
+import javax.security.auth.*;
+import javax.security.auth.callback.*;
+import javax.security.auth.login.*;
+import javax.security.auth.spi.*;
+
+/**
+ * This login module authenticates users by reading usernames, passwords, and roles from a text
+ * file.
+ */
+public class SimpleLoginModule implements LoginModule
+{
+ private Subject subject;
+ private CallbackHandler callbackHandler;
+ private Map options;
+
+ public void initialize(Subject subject, CallbackHandler callbackHandler,
+ Map sharedState, Map options)
+ {
+ this.subject = subject;
+ this.callbackHandler = callbackHandler;
+ this.options = options;
+ }
+
+ public boolean login() throws LoginException
+ {
+ if (callbackHandler == null) throw new LoginException("no handler");
+
+ NameCallback nameCall = new NameCallback("username: ");
+ PasswordCallback passCall = new PasswordCallback("password: ", false);
+ try
+ {
+ callbackHandler.handle(new Callback[] { nameCall, passCall });
+ }
+ catch (UnsupportedCallbackException e)
+ {
+ LoginException e2 = new LoginException("Unsupported callback");
+ e2.initCause(e);
+ throw e2;
+ }
+ catch (IOException e)
+ {
+ LoginException e2 = new LoginException("I/O exception in callback");
+ e2.initCause(e);
+ throw e2;
+ }
+
+ try
+ {
+ return checkLogin(nameCall.getName(), passCall.getPassword());
+ }
+ catch (IOException ex)
+ {
+ LoginException ex2 = new LoginException();
+ ex2.initCause(ex);
+ throw ex2;
+ }
+ }
+
+ /**
+ * Checks whether the authentication information is valid. If it is, the subject acquires
+ * principals for the user name and role.
+ * @param username the user name
+ * @param password a character array containing the password
+ * @return true if the authentication information is valid
+ */
+ private boolean checkLogin(String username, char[] password) throws LoginException, IOException
+ {
+ try (Scanner in = new Scanner(Paths.get("" + options.get("pwfile")), "UTF-8"))
+ {
+ while (in.hasNextLine())
+ {
+ String[] inputs = in.nextLine().split("\\|");
+ if (inputs[0].equals(username) && Arrays.equals(inputs[1].toCharArray(), password))
+ {
+ String role = inputs[2];
+ Set principals = subject.getPrincipals();
+ principals.add(new SimplePrincipal("username", username));
+ principals.add(new SimplePrincipal("role", role));
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ public boolean logout()
+ {
+ return true;
+ }
+
+ public boolean abort()
+ {
+ return true;
+ }
+
+ public boolean commit()
+ {
+ return true;
+ }
+}
diff --git a/corejava第10版/v2ch09/jaas/SimplePrincipal.java b/corejava第10版/v2ch09/jaas/SimplePrincipal.java
new file mode 100644
index 0000000..af9b094
--- /dev/null
+++ b/corejava第10版/v2ch09/jaas/SimplePrincipal.java
@@ -0,0 +1,47 @@
+package jaas;
+
+import java.security.*;
+import java.util.*;
+
+/**
+ * A principal with a named value (such as "role=HR" or "username=harry").
+ */
+public class SimplePrincipal implements Principal
+{
+ private String descr;
+ private String value;
+
+ /**
+ * Constructs a SimplePrincipal to hold a description and a value.
+ * @param descr the description
+ * @param value the associated value
+ */
+ public SimplePrincipal(String descr, String value)
+ {
+ this.descr = descr;
+ this.value = value;
+ }
+
+ /**
+ * Returns the role name of this principal.
+ * @return the role name
+ */
+ public String getName()
+ {
+ return descr + "=" + value;
+ }
+
+ public boolean equals(Object otherObject)
+ {
+ if (this == otherObject) return true;
+ if (otherObject == null) return false;
+ if (getClass() != otherObject.getClass()) return false;
+ SimplePrincipal other = (SimplePrincipal) otherObject;
+ return Objects.equals(getName(), other.getName());
+ }
+
+ public int hashCode()
+ {
+ return Objects.hashCode(getName());
+ }
+}
diff --git a/javacore第11版/corejava/v2ch10/jaas/SysPropAction.java b/corejava第10版/v2ch09/jaas/SysPropAction.java
similarity index 100%
rename from javacore第11版/corejava/v2ch10/jaas/SysPropAction.java
rename to corejava第10版/v2ch09/jaas/SysPropAction.java
diff --git a/javacore第11版/corejava/v2ch10/jaas/jaas.config b/corejava第10版/v2ch09/jaas/jaas.config
similarity index 100%
rename from javacore第11版/corejava/v2ch10/jaas/jaas.config
rename to corejava第10版/v2ch09/jaas/jaas.config
diff --git a/javacore第11版/corejava/v2ch10/jaas/password.txt b/corejava第10版/v2ch09/jaas/password.txt
similarity index 100%
rename from javacore第11版/corejava/v2ch10/jaas/password.txt
rename to corejava第10版/v2ch09/jaas/password.txt
diff --git a/corejava第10版/v2ch09/permissions/PermissionTest.java b/corejava第10版/v2ch09/permissions/PermissionTest.java
new file mode 100644
index 0000000..7122902
--- /dev/null
+++ b/corejava第10版/v2ch09/permissions/PermissionTest.java
@@ -0,0 +1,87 @@
+package permissions;
+
+import java.awt.*;
+
+import javax.swing.*;
+
+/**
+ * This class demonstrates the custom WordCheckPermission.
+ * @version 1.04 2016-05-10
+ * @author Cay Horstmann
+ */
+public class PermissionTest
+{
+ public static void main(String[] args)
+ {
+ System.setProperty("java.security.policy", "permissions/PermissionTest.policy");
+ System.setSecurityManager(new SecurityManager());
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new PermissionTestFrame();
+ frame.setTitle("PermissionTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * This frame contains a text field for inserting words into a text area that is protected from "bad
+ * words".
+ */
+class PermissionTestFrame extends JFrame
+{
+ private JTextField textField;
+ private WordCheckTextArea textArea;
+ private static final int TEXT_ROWS = 20;
+ private static final int TEXT_COLUMNS = 60;
+
+ public PermissionTestFrame()
+ {
+ textField = new JTextField(20);
+ JPanel panel = new JPanel();
+ panel.add(textField);
+ JButton openButton = new JButton("Insert");
+ panel.add(openButton);
+ openButton.addActionListener(event -> insertWords(textField.getText()));
+
+ add(panel, BorderLayout.NORTH);
+
+ textArea = new WordCheckTextArea();
+ textArea.setRows(TEXT_ROWS);
+ textArea.setColumns(TEXT_COLUMNS);
+ add(new JScrollPane(textArea), BorderLayout.CENTER);
+ pack();
+ }
+
+ /**
+ * Tries to insert words into the text area. Displays a dialog if the attempt fails.
+ * @param words the words to insert
+ */
+ public void insertWords(String words)
+ {
+ try
+ {
+ textArea.append(words + "\n");
+ }
+ catch (SecurityException ex)
+ {
+ JOptionPane.showMessageDialog(this, "I am sorry, but I cannot do that.");
+ ex.printStackTrace();
+ }
+ }
+}
+
+/**
+ * A text area whose append method makes a security check to see that no bad words are added.
+ */
+class WordCheckTextArea extends JTextArea
+{
+ public void append(String text)
+ {
+ WordCheckPermission p = new WordCheckPermission(text, "insert");
+ SecurityManager manager = System.getSecurityManager();
+ if (manager != null) manager.checkPermission(p);
+ super.append(text);
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v2ch10/permissions/PermissionTest.policy b/corejava第10版/v2ch09/permissions/PermissionTest.policy
similarity index 100%
rename from javacore第11版/corejava/v2ch10/permissions/PermissionTest.policy
rename to corejava第10版/v2ch09/permissions/PermissionTest.policy
diff --git a/corejava第10版/v2ch09/permissions/WordCheckPermission.java b/corejava第10版/v2ch09/permissions/WordCheckPermission.java
new file mode 100644
index 0000000..4210214
--- /dev/null
+++ b/corejava第10版/v2ch09/permissions/WordCheckPermission.java
@@ -0,0 +1,77 @@
+package permissions;
+
+import java.security.*;
+import java.util.*;
+
+/**
+ * A permission that checks for bad words.
+ */
+public class WordCheckPermission extends Permission
+{
+ private String action;
+
+ /**
+ * Constructs a word check permission.
+ * @param target a comma separated word list
+ * @param anAction "insert" or "avoid"
+ */
+ public WordCheckPermission(String target, String anAction)
+ {
+ super(target);
+ action = anAction;
+ }
+
+ public String getActions()
+ {
+ return action;
+ }
+
+ public boolean equals(Object other)
+ {
+ if (other == null) return false;
+ if (!getClass().equals(other.getClass())) return false;
+ WordCheckPermission b = (WordCheckPermission) other;
+ if (!Objects.equals(action, b.action)) return false;
+ if ("insert".equals(action)) return Objects.equals(getName(), b.getName());
+ else if ("avoid".equals(action)) return badWordSet().equals(b.badWordSet());
+ else return false;
+ }
+
+ public int hashCode()
+ {
+ return Objects.hash(getName(), action);
+ }
+
+ public boolean implies(Permission other)
+ {
+ if (!(other instanceof WordCheckPermission)) return false;
+ WordCheckPermission b = (WordCheckPermission) other;
+ if (action.equals("insert"))
+ {
+ return b.action.equals("insert") && getName().indexOf(b.getName()) >= 0;
+ }
+ else if (action.equals("avoid"))
+ {
+ if (b.action.equals("avoid")) return b.badWordSet().containsAll(badWordSet());
+ else if (b.action.equals("insert"))
+ {
+ for (String badWord : badWordSet())
+ if (b.getName().indexOf(badWord) >= 0) return false;
+ return true;
+ }
+ else return false;
+ }
+ else return false;
+ }
+
+ /**
+ * Gets the bad words that this permission rule describes.
+ * @return a set of the bad words
+ */
+ public Set badWordSet()
+ {
+ Set set = new HashSet<>();
+ set.addAll(Arrays.asList(getName().split(",")));
+ return set;
+ }
+}
diff --git a/corejava第10版/v2ch09/rsa/RSATest.java b/corejava第10版/v2ch09/rsa/RSATest.java
new file mode 100644
index 0000000..fb2d76d
--- /dev/null
+++ b/corejava第10版/v2ch09/rsa/RSATest.java
@@ -0,0 +1,85 @@
+package rsa;
+
+import java.io.*;
+import java.security.*;
+import javax.crypto.*;
+
+/**
+ * This program tests the RSA cipher. Usage:
+ * java rsa.RSATest -genkey public private
+ * java rsa.RSATest -encrypt plaintext encrypted public
+ * java rsa.RSATest -decrypt encrypted decrypted private
+ * @author Cay Horstmann
+ * @version 1.01 2012-06-10
+ */
+public class RSATest
+{
+ private static final int KEYSIZE = 512;
+
+ public static void main(String[] args)
+ throws IOException, GeneralSecurityException, ClassNotFoundException
+ {
+ if (args[0].equals("-genkey"))
+ {
+ KeyPairGenerator pairgen = KeyPairGenerator.getInstance("RSA");
+ SecureRandom random = new SecureRandom();
+ pairgen.initialize(KEYSIZE, random);
+ KeyPair keyPair = pairgen.generateKeyPair();
+ try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(args[1])))
+ {
+ out.writeObject(keyPair.getPublic());
+ }
+ try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(args[2])))
+ {
+ out.writeObject(keyPair.getPrivate());
+ }
+ }
+ else if (args[0].equals("-encrypt"))
+ {
+ KeyGenerator keygen = KeyGenerator.getInstance("AES");
+ SecureRandom random = new SecureRandom();
+ keygen.init(random);
+ SecretKey key = keygen.generateKey();
+
+ // wrap with RSA public key
+ try (ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(args[3]));
+ DataOutputStream out = new DataOutputStream(new FileOutputStream(args[2]));
+ InputStream in = new FileInputStream(args[1]) )
+ {
+ Key publicKey = (Key) keyIn.readObject();
+ Cipher cipher = Cipher.getInstance("RSA");
+ cipher.init(Cipher.WRAP_MODE, publicKey);
+ byte[] wrappedKey = cipher.wrap(key);
+ out.writeInt(wrappedKey.length);
+ out.write(wrappedKey);
+
+ cipher = Cipher.getInstance("AES");
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ Util.crypt(in, out, cipher);
+ }
+ }
+ else
+ {
+ try (DataInputStream in = new DataInputStream(new FileInputStream(args[1]));
+ ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(args[3]));
+ OutputStream out = new FileOutputStream(args[2]))
+ {
+ int length = in.readInt();
+ byte[] wrappedKey = new byte[length];
+ in.read(wrappedKey, 0, length);
+
+ // unwrap with RSA private key
+ Key privateKey = (Key) keyIn.readObject();
+
+ Cipher cipher = Cipher.getInstance("RSA");
+ cipher.init(Cipher.UNWRAP_MODE, privateKey);
+ Key key = cipher.unwrap(wrappedKey, "AES", Cipher.SECRET_KEY);
+
+ cipher = Cipher.getInstance("AES");
+ cipher.init(Cipher.DECRYPT_MODE, key);
+
+ Util.crypt(in, out, cipher);
+ }
+ }
+ }
+}
diff --git a/corejava第10版/v2ch09/rsa/Util.java b/corejava第10版/v2ch09/rsa/Util.java
new file mode 100644
index 0000000..c3c47ea
--- /dev/null
+++ b/corejava第10版/v2ch09/rsa/Util.java
@@ -0,0 +1,41 @@
+package rsa;
+
+import java.io.*;
+import java.security.*;
+import javax.crypto.*;
+
+public class Util
+{
+ /**
+ * Uses a cipher to transform the bytes in an input stream and sends the transformed bytes to an
+ * output stream.
+ * @param in the input stream
+ * @param out the output stream
+ * @param cipher the cipher that transforms the bytes
+ */
+ public static void crypt(InputStream in, OutputStream out, Cipher cipher) throws IOException,
+ GeneralSecurityException
+ {
+ int blockSize = cipher.getBlockSize();
+ int outputSize = cipher.getOutputSize(blockSize);
+ byte[] inBytes = new byte[blockSize];
+ byte[] outBytes = new byte[outputSize];
+
+ int inLength = 0;
+ ;
+ boolean more = true;
+ while (more)
+ {
+ inLength = in.read(inBytes);
+ if (inLength == blockSize)
+ {
+ int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
+ out.write(outBytes, 0, outLength);
+ }
+ else more = false;
+ }
+ if (inLength > 0) outBytes = cipher.doFinal(inBytes, 0, inLength);
+ else outBytes = cipher.doFinal();
+ out.write(outBytes);
+ }
+}
diff --git a/corejava第10版/v2ch09/signed/FileReadApplet.java b/corejava第10版/v2ch09/signed/FileReadApplet.java
new file mode 100644
index 0000000..d8e0b77
--- /dev/null
+++ b/corejava第10版/v2ch09/signed/FileReadApplet.java
@@ -0,0 +1,61 @@
+package signed;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.nio.file.*;
+import javax.swing.*;
+
+/**
+ * This applet can run "outside the sandbox" and read local files when it is given the right
+ * permissions.
+ * @version 1.13 2016-05-10
+ * @author Cay Horstmann
+ */
+public class FileReadApplet extends JApplet
+{
+ private JTextField fileNameField;
+ private JTextArea fileText;
+
+ public void init()
+ {
+ EventQueue.invokeLater(() ->
+ {
+ fileNameField = new JTextField(20);
+ JPanel panel = new JPanel();
+ panel.add(new JLabel("File name:"));
+ panel.add(fileNameField);
+ JButton openButton = new JButton("Open");
+ panel.add(openButton);
+ ActionListener listener = event -> loadFile(fileNameField.getText());
+ fileNameField.addActionListener(listener);
+ openButton.addActionListener(listener);
+ add(panel, "North");
+ fileText = new JTextArea();
+ add(new JScrollPane(fileText), "Center");
+ });
+ }
+
+ /**
+ * Loads the contents of a file into the text area.
+ * @param filename the file name
+ */
+ public void loadFile(String filename)
+ {
+ fileText.setText("");
+ try
+ {
+ fileText.append(new String(Files.readAllBytes(Paths.get(filename))));
+ }
+ catch (IOException ex)
+ {
+ fileText.append(ex + "\n");
+ }
+ catch (SecurityException ex)
+ {
+ fileText.append("I am sorry, but I cannot do that.\n");
+ fileText.append(ex + "\n");
+ ex.printStackTrace();
+ }
+ }
+}
diff --git a/javacore第11版/corejava/v2ch10/verifier/VerifierTest.html b/corejava第10版/v2ch09/verifier/VerifierTest.html
similarity index 100%
rename from javacore第11版/corejava/v2ch10/verifier/VerifierTest.html
rename to corejava第10版/v2ch09/verifier/VerifierTest.html
diff --git a/corejava第10版/v2ch09/verifier/VerifierTest.java b/corejava第10版/v2ch09/verifier/VerifierTest.java
new file mode 100644
index 0000000..632556b
--- /dev/null
+++ b/corejava第10版/v2ch09/verifier/VerifierTest.java
@@ -0,0 +1,38 @@
+package verifier;
+
+import java.applet.*;
+import java.awt.*;
+
+/**
+ * This application demonstrates the bytecode verifier of the virtual machine. If you use a hex
+ * editor to modify the class file, then the virtual machine should detect the tampering.
+ * @version 1.00 1997-09-10
+ * @author Cay Horstmann
+ */
+public class VerifierTest extends Applet
+{
+ public static void main(String[] args)
+ {
+ System.out.println("1 + 2 == " + fun());
+ }
+
+ /**
+ * A function that computes 1 + 2.
+ * @return 3, if the code has not been corrupted
+ */
+ public static int fun()
+ {
+ int m;
+ int n;
+ m = 1;
+ n = 2;
+ // use hex editor to change to "m = 2" in class file
+ int r = m + n;
+ return r;
+ }
+
+ public void paint(Graphics g)
+ {
+ g.drawString("1 + 2 == " + fun(), 20, 20);
+ }
+}
diff --git a/corejava第10版/v2ch10/editorPane/EditorPaneFrame.java b/corejava第10版/v2ch10/editorPane/EditorPaneFrame.java
new file mode 100644
index 0000000..b84fbc8
--- /dev/null
+++ b/corejava第10版/v2ch10/editorPane/EditorPaneFrame.java
@@ -0,0 +1,110 @@
+package editorPane;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.event.*;
+
+/**
+ * This frame contains an editor pane, a text field and button to enter a URL and load a document,
+ * and a Back button to return to a previously loaded document.
+ */
+public class EditorPaneFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 600;
+ private static final int DEFAULT_HEIGHT = 400;
+
+ public EditorPaneFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ final Stack urlStack = new Stack<>();
+ final JEditorPane editorPane = new JEditorPane();
+ final JTextField url = new JTextField(30);
+
+ // set up hyperlink listener
+
+ editorPane.setEditable(false);
+ editorPane.addHyperlinkListener(event ->
+ {
+ if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED)
+ {
+ try
+ {
+ // remember URL for back button
+ urlStack.push(event.getURL().toString());
+ // show URL in text field
+ url.setText(event.getURL().toString());
+ editorPane.setPage(event.getURL());
+ }
+ catch (IOException e)
+ {
+ editorPane.setText("Exception: " + e);
+ }
+ }
+ });
+
+ // set up checkbox for toggling edit mode
+
+ final JCheckBox editable = new JCheckBox();
+ editable.addActionListener(event ->
+ editorPane.setEditable(editable.isSelected()));
+
+ // set up load button for loading URL
+
+ ActionListener listener = event ->
+ {
+ try
+ {
+ // remember URL for back button
+ urlStack.push(url.getText());
+ editorPane.setPage(url.getText());
+ }
+ catch (IOException e)
+ {
+ editorPane.setText("Exception: " + e);
+ }
+ };
+
+ JButton loadButton = new JButton("Load");
+ loadButton.addActionListener(listener);
+ url.addActionListener(listener);
+
+ // set up back button and button action
+
+ JButton backButton = new JButton("Back");
+ backButton.addActionListener(event ->
+ {
+ if (urlStack.size() <= 1) return;
+ try
+ {
+ // get URL from back button
+ urlStack.pop();
+ // show URL in text field
+ String urlString = urlStack.peek();
+ url.setText(urlString);
+ editorPane.setPage(urlString);
+ }
+ catch (IOException e)
+ {
+ editorPane.setText("Exception: " + e);
+ }
+ });
+
+ add(new JScrollPane(editorPane), BorderLayout.CENTER);
+
+ // put all control components in a panel
+
+ JPanel panel = new JPanel();
+ panel.add(new JLabel("URL"));
+ panel.add(url);
+ panel.add(loadButton);
+ panel.add(backButton);
+ panel.add(new JLabel("Editable"));
+ panel.add(editable);
+
+ add(panel, BorderLayout.SOUTH);
+ }
+}
diff --git a/corejava第10版/v2ch10/editorPane/EditorPaneTest.java b/corejava第10版/v2ch10/editorPane/EditorPaneTest.java
new file mode 100644
index 0000000..1cb3ad6
--- /dev/null
+++ b/corejava第10版/v2ch10/editorPane/EditorPaneTest.java
@@ -0,0 +1,23 @@
+package editorPane;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates how to display HTML documents in an editor pane.
+ * @version 1.05 2016-05-10
+ * @author Cay Horstmann
+ */
+public class EditorPaneTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new EditorPaneFrame();
+ frame.setTitle("EditorPaneTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
diff --git a/corejava第10版/v2ch10/internalFrame/DesktopFrame.java b/corejava第10版/v2ch10/internalFrame/DesktopFrame.java
new file mode 100644
index 0000000..3998070
--- /dev/null
+++ b/corejava第10版/v2ch10/internalFrame/DesktopFrame.java
@@ -0,0 +1,243 @@
+package internalFrame;
+
+import java.awt.*;
+import java.beans.*;
+
+import javax.swing.*;
+
+/**
+ * This desktop frame contains editor panes that show HTML documents.
+ */
+public class DesktopFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 600;
+ private static final int DEFAULT_HEIGHT = 400;
+ private static final String[] planets = { "Mercury", "Venus", "Earth", "Mars", "Jupiter",
+ "Saturn", "Uranus", "Neptune", "Pluto", };
+
+ private JDesktopPane desktop;
+ private int nextFrameX;
+ private int nextFrameY;
+ private int frameDistance;
+ private int counter;
+
+ public DesktopFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ desktop = new JDesktopPane();
+ add(desktop, BorderLayout.CENTER);
+
+ // set up menus
+
+ JMenuBar menuBar = new JMenuBar();
+ setJMenuBar(menuBar);
+ JMenu fileMenu = new JMenu("File");
+ menuBar.add(fileMenu);
+ JMenuItem openItem = new JMenuItem("New");
+ openItem.addActionListener(event ->
+ {
+ createInternalFrame(new JLabel(
+ new ImageIcon(getClass().getResource(planets[counter] + ".gif"))),
+ planets[counter]);
+ counter = (counter + 1) % planets.length;
+ });
+ fileMenu.add(openItem);
+ JMenuItem exitItem = new JMenuItem("Exit");
+ exitItem.addActionListener(event -> System.exit(0));
+ fileMenu.add(exitItem);
+ JMenu windowMenu = new JMenu("Window");
+ menuBar.add(windowMenu);
+ JMenuItem nextItem = new JMenuItem("Next");
+ nextItem.addActionListener(event -> selectNextWindow());
+ windowMenu.add(nextItem);
+ JMenuItem cascadeItem = new JMenuItem("Cascade");
+ cascadeItem.addActionListener(event -> cascadeWindows());
+ windowMenu.add(cascadeItem);
+ JMenuItem tileItem = new JMenuItem("Tile");
+ tileItem.addActionListener(event -> tileWindows());
+ windowMenu.add(tileItem);
+ final JCheckBoxMenuItem dragOutlineItem = new JCheckBoxMenuItem("Drag Outline");
+ dragOutlineItem.addActionListener(event ->
+ desktop.setDragMode(dragOutlineItem.isSelected() ? JDesktopPane.OUTLINE_DRAG_MODE
+ : JDesktopPane.LIVE_DRAG_MODE));
+ windowMenu.add(dragOutlineItem);
+ }
+
+ /**
+ * Creates an internal frame on the desktop.
+ * @param c the component to display in the internal frame
+ * @param t the title of the internal frame
+ */
+ public void createInternalFrame(Component c, String t)
+ {
+ final JInternalFrame iframe = new JInternalFrame(t, true, // resizable
+ true, // closable
+ true, // maximizable
+ true); // iconifiable
+
+ iframe.add(c, BorderLayout.CENTER);
+ desktop.add(iframe);
+
+ iframe.setFrameIcon(new ImageIcon(getClass().getResource("document.gif")));
+
+ // add listener to confirm frame closing
+ iframe.addVetoableChangeListener(event ->
+ {
+ String name = event.getPropertyName();
+ Object value = event.getNewValue();
+
+ // we only want to check attempts to close a frame
+ if (name.equals("closed") && value.equals(true))
+ {
+ // ask user if it is ok to close
+ int result = JOptionPane.showInternalConfirmDialog(iframe, "OK to close?",
+ "Select an Option", JOptionPane.YES_NO_OPTION);
+
+ // if the user doesn't agree, veto the close
+ if (result != JOptionPane.YES_OPTION) throw new PropertyVetoException(
+ "User canceled close", event);
+ }
+ });
+
+ // position frame
+ int width = desktop.getWidth() / 2;
+ int height = desktop.getHeight() / 2;
+ iframe.reshape(nextFrameX, nextFrameY, width, height);
+
+ iframe.show();
+
+ // select the frame--might be vetoed
+ try
+ {
+ iframe.setSelected(true);
+ }
+ catch (PropertyVetoException ex)
+ {
+ }
+
+ frameDistance = iframe.getHeight() - iframe.getContentPane().getHeight();
+
+ // compute placement for next frame
+
+ nextFrameX += frameDistance;
+ nextFrameY += frameDistance;
+ if (nextFrameX + width > desktop.getWidth()) nextFrameX = 0;
+ if (nextFrameY + height > desktop.getHeight()) nextFrameY = 0;
+ }
+
+ /**
+ * Cascades the noniconified internal frames of the desktop.
+ */
+ public void cascadeWindows()
+ {
+ int x = 0;
+ int y = 0;
+ int width = desktop.getWidth() / 2;
+ int height = desktop.getHeight() / 2;
+
+ for (JInternalFrame frame : desktop.getAllFrames())
+ {
+ if (!frame.isIcon())
+ {
+ try
+ {
+ // try to make maximized frames resizable; this might be vetoed
+ frame.setMaximum(false);
+ frame.reshape(x, y, width, height);
+
+ x += frameDistance;
+ y += frameDistance;
+ // wrap around at the desktop edge
+ if (x + width > desktop.getWidth()) x = 0;
+ if (y + height > desktop.getHeight()) y = 0;
+ }
+ catch (PropertyVetoException ex)
+ {
+ }
+ }
+ }
+ }
+
+ /**
+ * Tiles the noniconified internal frames of the desktop.
+ */
+ public void tileWindows()
+ {
+ // count frames that aren't iconized
+ int frameCount = 0;
+ for (JInternalFrame frame : desktop.getAllFrames())
+ if (!frame.isIcon()) frameCount++;
+ if (frameCount == 0) return;
+
+ int rows = (int) Math.sqrt(frameCount);
+ int cols = frameCount / rows;
+ int extra = frameCount % rows;
+ // number of columns with an extra row
+
+ int width = desktop.getWidth() / cols;
+ int height = desktop.getHeight() / rows;
+ int r = 0;
+ int c = 0;
+ for (JInternalFrame frame : desktop.getAllFrames())
+ {
+ if (!frame.isIcon())
+ {
+ try
+ {
+ frame.setMaximum(false);
+ frame.reshape(c * width, r * height, width, height);
+ r++;
+ if (r == rows)
+ {
+ r = 0;
+ c++;
+ if (c == cols - extra)
+ {
+ // start adding an extra row
+ rows++;
+ height = desktop.getHeight() / rows;
+ }
+ }
+ }
+ catch (PropertyVetoException ex)
+ {
+ }
+ }
+ }
+ }
+
+ /**
+ * Brings the next noniconified internal frame to the front.
+ */
+ public void selectNextWindow()
+ {
+ JInternalFrame[] frames = desktop.getAllFrames();
+ for (int i = 0; i < frames.length; i++)
+ {
+ if (frames[i].isSelected())
+ {
+ // find next frame that isn't an icon and can be selected
+ int next = (i + 1) % frames.length;
+ while (next != i)
+ {
+ if (!frames[next].isIcon())
+ {
+ try
+ {
+ // all other frames are icons or veto selection
+ frames[next].setSelected(true);
+ frames[next].toFront();
+ frames[i].toBack();
+ return;
+ }
+ catch (PropertyVetoException ex)
+ {
+ }
+ }
+ next = (next + 1) % frames.length;
+ }
+ }
+ }
+ }
+}
diff --git a/javacore第11版/corejava/v2ch11/tableCellRender/Earth.gif b/corejava第10版/v2ch10/internalFrame/Earth.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/tableCellRender/Earth.gif
rename to corejava第10版/v2ch10/internalFrame/Earth.gif
diff --git a/corejava第10版/v2ch10/internalFrame/InternalFrameTest.java b/corejava第10版/v2ch10/internalFrame/InternalFrameTest.java
new file mode 100644
index 0000000..ff06b4b
--- /dev/null
+++ b/corejava第10版/v2ch10/internalFrame/InternalFrameTest.java
@@ -0,0 +1,23 @@
+package internalFrame;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates the use of internal frames.
+ * @version 1.12 2016-05-10
+ * @author Cay Horstmann
+ */
+public class InternalFrameTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new DesktopFrame();
+ frame.setTitle("InternalFrameTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v2ch11/tableCellRender/Jupiter.gif b/corejava第10版/v2ch10/internalFrame/Jupiter.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/tableCellRender/Jupiter.gif
rename to corejava第10版/v2ch10/internalFrame/Jupiter.gif
diff --git a/javacore第11版/corejava/v2ch11/tableCellRender/Mars.gif b/corejava第10版/v2ch10/internalFrame/Mars.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/tableCellRender/Mars.gif
rename to corejava第10版/v2ch10/internalFrame/Mars.gif
diff --git a/javacore第11版/corejava/v2ch11/tableCellRender/Mercury.gif b/corejava第10版/v2ch10/internalFrame/Mercury.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/tableCellRender/Mercury.gif
rename to corejava第10版/v2ch10/internalFrame/Mercury.gif
diff --git a/javacore第11版/corejava/v2ch11/tableCellRender/Neptune.gif b/corejava第10版/v2ch10/internalFrame/Neptune.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/tableCellRender/Neptune.gif
rename to corejava第10版/v2ch10/internalFrame/Neptune.gif
diff --git a/javacore第11版/corejava/v2ch11/tableCellRender/Pluto.gif b/corejava第10版/v2ch10/internalFrame/Pluto.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/tableCellRender/Pluto.gif
rename to corejava第10版/v2ch10/internalFrame/Pluto.gif
diff --git a/javacore第11版/corejava/v2ch11/tableCellRender/Saturn.gif b/corejava第10版/v2ch10/internalFrame/Saturn.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/tableCellRender/Saturn.gif
rename to corejava第10版/v2ch10/internalFrame/Saturn.gif
diff --git a/javacore第11版/corejava/v2ch11/tableCellRender/Uranus.gif b/corejava第10版/v2ch10/internalFrame/Uranus.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/tableCellRender/Uranus.gif
rename to corejava第10版/v2ch10/internalFrame/Uranus.gif
diff --git a/javacore第11版/corejava/v2ch11/tableCellRender/Venus.gif b/corejava第10版/v2ch10/internalFrame/Venus.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/tableCellRender/Venus.gif
rename to corejava第10版/v2ch10/internalFrame/Venus.gif
diff --git a/javacore第11版/corejava/v2ch11/treeRender/yellow-ball.gif b/corejava第10版/v2ch10/internalFrame/document.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/treeRender/yellow-ball.gif
rename to corejava第10版/v2ch10/internalFrame/document.gif
diff --git a/corejava第10版/v2ch10/layer/ColorFrame.java b/corejava第10版/v2ch10/layer/ColorFrame.java
new file mode 100644
index 0000000..01281bd
--- /dev/null
+++ b/corejava第10版/v2ch10/layer/ColorFrame.java
@@ -0,0 +1,89 @@
+package layer;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.plaf.*;
+
+/**
+ * A frame with three text fields to set the background color.
+ */
+public class ColorFrame extends JFrame
+{
+ private JPanel panel;
+ private JTextField redField;
+ private JTextField greenField;
+ private JTextField blueField;
+
+ public ColorFrame()
+ {
+ panel = new JPanel();
+
+ panel.add(new JLabel("Red:"));
+ redField = new JTextField("255", 3);
+ panel.add(redField);
+
+ panel.add(new JLabel("Green:"));
+ greenField = new JTextField("255", 3);
+ panel.add(greenField);
+
+ panel.add(new JLabel("Blue:"));
+ blueField = new JTextField("255", 3);
+ panel.add(blueField);
+
+ LayerUI layerUI = new PanelLayer();
+ JLayer layer = new JLayer(panel, layerUI);
+
+ add(layer);
+ pack();
+ }
+
+ class PanelLayer extends LayerUI
+ {
+ public void installUI(JComponent c)
+ {
+ super.installUI(c);
+ ((JLayer>) c).setLayerEventMask(AWTEvent.KEY_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK);
+ }
+
+ public void uninstallUI(JComponent c)
+ {
+ ((JLayer>) c).setLayerEventMask(0);
+ super.uninstallUI(c);
+ }
+
+ protected void processKeyEvent(KeyEvent e, JLayer extends JPanel> l)
+ {
+ l.repaint();
+ }
+
+ protected void processFocusEvent(FocusEvent e, JLayer extends JPanel> l)
+ {
+ if (e.getID() == FocusEvent.FOCUS_GAINED)
+ {
+ Component c = e.getComponent();
+ c.setFont(getFont().deriveFont(Font.BOLD));
+ }
+ if (e.getID() == FocusEvent.FOCUS_LOST)
+ {
+ Component c = e.getComponent();
+ c.setFont(getFont().deriveFont(Font.PLAIN));
+ }
+ }
+
+ public void paint(Graphics g, JComponent c)
+ {
+ super.paint(g, c);
+
+ Graphics2D g2 = (Graphics2D) g.create();
+ g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .3f));
+ int red = Integer.parseInt(redField.getText().trim());
+ int green = Integer.parseInt(greenField.getText().trim());
+ int blue = Integer.parseInt(blueField.getText().trim());
+ g2.setPaint(new Color(red, green, blue));
+ g2.fillRect(0, 0, c.getWidth(), c.getHeight());
+ g2.dispose();
+ }
+ }
+}
+
diff --git a/corejava第10版/v2ch10/layer/LayerTest.java b/corejava第10版/v2ch10/layer/LayerTest.java
new file mode 100644
index 0000000..e7d75b8
--- /dev/null
+++ b/corejava第10版/v2ch10/layer/LayerTest.java
@@ -0,0 +1,23 @@
+package layer;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates how a layer can decorate a Swing component.
+ * @version 1.01 2016-05-10
+ * @author Cay Horstmann
+ */
+public class LayerTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new ColorFrame();
+ frame.setTitle("LayerTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/list/ListFrame.java b/corejava第10版/v2ch10/list/ListFrame.java
new file mode 100644
index 0000000..9661234
--- /dev/null
+++ b/corejava第10版/v2ch10/list/ListFrame.java
@@ -0,0 +1,79 @@
+package list;
+
+import java.awt.*;
+
+import javax.swing.*;
+
+/**
+ * This frame contains a word list and a label that shows a sentence made up from the chosen words.
+ * Note that you can select multiple words with Ctrl+click and Shift+click.
+ */
+class ListFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 400;
+ private static final int DEFAULT_HEIGHT = 300;
+
+ private JPanel listPanel;
+ private JList wordList;
+ private JLabel label;
+ private JPanel buttonPanel;
+ private ButtonGroup group;
+ private String prefix = "The ";
+ private String suffix = "fox jumps over the lazy dog.";
+
+ public ListFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ String[] words = { "quick", "brown", "hungry", "wild", "silent", "huge", "private",
+ "abstract", "static", "final" };
+
+ wordList = new JList<>(words);
+ wordList.setVisibleRowCount(4);
+ JScrollPane scrollPane = new JScrollPane(wordList);
+
+ listPanel = new JPanel();
+ listPanel.add(scrollPane);
+ wordList.addListSelectionListener(event ->
+ {
+ StringBuilder text = new StringBuilder(prefix);
+ for (String value : wordList.getSelectedValuesList())
+ {
+ text.append(value);
+ text.append(" ");
+ }
+ text.append(suffix);
+
+ label.setText(text.toString());
+ });
+
+ buttonPanel = new JPanel();
+ group = new ButtonGroup();
+ makeButton("Vertical", JList.VERTICAL);
+ makeButton("Vertical Wrap", JList.VERTICAL_WRAP);
+ makeButton("Horizontal Wrap", JList.HORIZONTAL_WRAP);
+
+ add(listPanel, BorderLayout.NORTH);
+ label = new JLabel(prefix + suffix);
+ add(label, BorderLayout.CENTER);
+ add(buttonPanel, BorderLayout.SOUTH);
+ }
+
+ /**
+ * Makes a radio button to set the layout orientation.
+ * @param label the button label
+ * @param orientation the orientation for the list
+ */
+ private void makeButton(String label, final int orientation)
+ {
+ JRadioButton button = new JRadioButton(label);
+ buttonPanel.add(button);
+ if (group.getButtonCount() == 0) button.setSelected(true);
+ group.add(button);
+ button.addActionListener(event ->
+ {
+ wordList.setLayoutOrientation(orientation);
+ listPanel.revalidate();
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/list/ListTest.java b/corejava第10版/v2ch10/list/ListTest.java
new file mode 100644
index 0000000..3d14b79
--- /dev/null
+++ b/corejava第10版/v2ch10/list/ListTest.java
@@ -0,0 +1,23 @@
+package list;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates a simple fixed list of strings.
+ * @version 1.25 2016-05-10
+ * @author Cay Horstmann
+ */
+public class ListTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new ListFrame();
+ frame.setTitle("ListTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/listRendering/FontCellRenderer.java b/corejava第10版/v2ch10/listRendering/FontCellRenderer.java
new file mode 100644
index 0000000..a3be4b2
--- /dev/null
+++ b/corejava第10版/v2ch10/listRendering/FontCellRenderer.java
@@ -0,0 +1,42 @@
+package listRendering;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * A cell renderer for Font objects that renders the font name in its own font.
+ */
+public class FontCellRenderer extends JComponent implements ListCellRenderer
+{
+ private Font font;
+ private Color background;
+ private Color foreground;
+
+ public Component getListCellRendererComponent(JList extends Font> list,
+ Font value, int index, boolean isSelected, boolean cellHasFocus)
+ {
+ font = value;
+ background = isSelected ? list.getSelectionBackground() : list.getBackground();
+ foreground = isSelected ? list.getSelectionForeground() : list.getForeground();
+ return this;
+ }
+
+ public void paintComponent(Graphics g)
+ {
+ String text = font.getFamily();
+ FontMetrics fm = g.getFontMetrics(font);
+ g.setColor(background);
+ g.fillRect(0, 0, getWidth(), getHeight());
+ g.setColor(foreground);
+ g.setFont(font);
+ g.drawString(text, 0, fm.getAscent());
+ }
+
+ public Dimension getPreferredSize()
+ {
+ String text = font.getFamily();
+ Graphics g = getGraphics();
+ FontMetrics fm = g.getFontMetrics(font);
+ return new Dimension(fm.stringWidth(text), fm.getHeight());
+ }
+}
diff --git a/corejava第10版/v2ch10/listRendering/ListRenderingFrame.java b/corejava第10版/v2ch10/listRendering/ListRenderingFrame.java
new file mode 100644
index 0000000..37a2714
--- /dev/null
+++ b/corejava第10版/v2ch10/listRendering/ListRenderingFrame.java
@@ -0,0 +1,52 @@
+package listRendering;
+
+import java.awt.*;
+import java.util.*;
+
+import javax.swing.*;
+
+/**
+ * This frame contains a list with a set of fonts and a text area that is set to the selected font.
+ */
+public class ListRenderingFrame extends JFrame
+{
+ private static final int TEXT_ROWS = 8;
+ private static final int TEXT_COLUMNS = 20;
+
+ private JTextArea text;
+ private JList fontList;
+
+ public ListRenderingFrame()
+ {
+ java.util.List fonts = new ArrayList<>();
+ final int SIZE = 24;
+ fonts.add(new Font("Serif", Font.PLAIN, SIZE));
+ fonts.add(new Font("SansSerif", Font.PLAIN, SIZE));
+ fonts.add(new Font("Monospaced", Font.PLAIN, SIZE));
+ fonts.add(new Font("Dialog", Font.PLAIN, SIZE));
+ fonts.add(new Font("DialogInput", Font.PLAIN, SIZE));
+ fontList = new JList(fonts.toArray(new Font[]{}));
+ fontList.setVisibleRowCount(4);
+ fontList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ fontList.setCellRenderer(new FontCellRenderer());
+ JScrollPane scrollPane = new JScrollPane(fontList);
+
+ JPanel p = new JPanel();
+ p.add(scrollPane);
+ fontList.addListSelectionListener(event ->
+ {
+ Font font = fontList.getSelectedValue();
+ text.setFont(font);
+ });
+
+ Container contentPane = getContentPane();
+ contentPane.add(p, BorderLayout.SOUTH);
+ text = new JTextArea(TEXT_ROWS, TEXT_COLUMNS);
+ text.setText("The quick brown fox jumps over the lazy dog");
+ text.setFont(fonts.get(0));
+ text.setLineWrap(true);
+ text.setWrapStyleWord(true);
+ contentPane.add(text, BorderLayout.CENTER);
+ pack();
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/listRendering/ListRenderingTest.java b/corejava第10版/v2ch10/listRendering/ListRenderingTest.java
new file mode 100644
index 0000000..65ff9c2
--- /dev/null
+++ b/corejava第10版/v2ch10/listRendering/ListRenderingTest.java
@@ -0,0 +1,23 @@
+package listRendering;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates the use of cell renderers in a list box.
+ * @version 1.25 2016-05-10
+ * @author Cay Horstmann
+ */
+public class ListRenderingTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new ListRenderingFrame();
+ frame.setTitle("ListRenderingTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/longList/LongListFrame.java b/corejava第10版/v2ch10/longList/LongListFrame.java
new file mode 100644
index 0000000..3205bd6
--- /dev/null
+++ b/corejava第10版/v2ch10/longList/LongListFrame.java
@@ -0,0 +1,48 @@
+package longList;
+
+import java.awt.*;
+
+import javax.swing.*;
+
+/**
+ * This frame contains a long word list and a label that shows a sentence made up from the chosen
+ * word.
+ */
+public class LongListFrame extends JFrame
+{
+ private JList wordList;
+ private JLabel label;
+ private String prefix = "The quick brown ";
+ private String suffix = " jumps over the lazy dog.";
+
+ public LongListFrame()
+ {
+ wordList = new JList(new WordListModel(3));
+ wordList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+ wordList.setPrototypeCellValue("www");
+ JScrollPane scrollPane = new JScrollPane(wordList);
+
+ JPanel p = new JPanel();
+ p.add(scrollPane);
+ wordList.addListSelectionListener(event -> setSubject(wordList.getSelectedValue()));
+
+ Container contentPane = getContentPane();
+ contentPane.add(p, BorderLayout.NORTH);
+ label = new JLabel(prefix + suffix);
+ contentPane.add(label, BorderLayout.CENTER);
+ setSubject("fox");
+ pack();
+ }
+
+ /**
+ * Sets the subject in the label.
+ * @param word the new subject that jumps over the lazy dog
+ */
+ public void setSubject(String word)
+ {
+ StringBuilder text = new StringBuilder(prefix);
+ text.append(word);
+ text.append(suffix);
+ label.setText(text.toString());
+ }
+}
diff --git a/corejava第10版/v2ch10/longList/LongListTest.java b/corejava第10版/v2ch10/longList/LongListTest.java
new file mode 100644
index 0000000..1680016
--- /dev/null
+++ b/corejava第10版/v2ch10/longList/LongListTest.java
@@ -0,0 +1,25 @@
+package longList;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates a list that dynamically computes list entries.
+ * @version 1.24 2016-05-10
+ * @author Cay Horstmann
+ */
+public class LongListTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new LongListFrame();
+ frame.setTitle("LongListTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+
diff --git a/corejava第10版/v2ch10/longList/WordListModel.java b/corejava第10版/v2ch10/longList/WordListModel.java
new file mode 100644
index 0000000..6a5e225
--- /dev/null
+++ b/corejava第10版/v2ch10/longList/WordListModel.java
@@ -0,0 +1,40 @@
+package longList;
+
+import javax.swing.*;
+
+/**
+ * A model that dynamically generates n-letter words.
+ */
+public class WordListModel extends AbstractListModel
+{
+ private int length;
+ public static final char FIRST = 'a';
+ public static final char LAST = 'z';
+
+ /**
+ * Constructs the model.
+ * @param n the word length
+ */
+ public WordListModel(int n)
+ {
+ length = n;
+ }
+
+ public int getSize()
+ {
+ return (int) Math.pow(LAST - FIRST + 1, length);
+ }
+
+ public String getElementAt(int n)
+ {
+ StringBuilder r = new StringBuilder();
+
+ for (int i = 0; i < length; i++)
+ {
+ char c = (char) (FIRST + n % (LAST - FIRST + 1));
+ r.insert(0, c);
+ n = n / (LAST - FIRST + 1);
+ }
+ return r.toString();
+ }
+}
diff --git a/corejava第10版/v2ch10/progressBar/ProgressBarFrame.java b/corejava第10版/v2ch10/progressBar/ProgressBarFrame.java
new file mode 100644
index 0000000..e7357b9
--- /dev/null
+++ b/corejava第10版/v2ch10/progressBar/ProgressBarFrame.java
@@ -0,0 +1,106 @@
+package progressBar;
+
+import java.awt.*;
+import java.util.List;
+
+import javax.swing.*;
+
+/**
+ * A frame that contains a button to launch a simulated activity, a progress bar, and a text area
+ * for the activity output.
+ */
+public class ProgressBarFrame extends JFrame
+{
+ public static final int TEXT_ROWS = 10;
+ public static final int TEXT_COLUMNS = 40;
+
+ private JButton startButton;
+ private JProgressBar progressBar;
+ private JCheckBox checkBox;
+ private JTextArea textArea;
+ private SimulatedActivity activity;
+
+ public ProgressBarFrame()
+ {
+ // this text area holds the activity output
+ textArea = new JTextArea(TEXT_ROWS, TEXT_COLUMNS);
+
+ // set up panel with button and progress bar
+
+ final int MAX = 1000;
+ JPanel panel = new JPanel();
+ startButton = new JButton("Start");
+ progressBar = new JProgressBar(0, MAX);
+ progressBar.setStringPainted(true);
+ panel.add(startButton);
+ panel.add(progressBar);
+
+ checkBox = new JCheckBox("indeterminate");
+ checkBox.addActionListener(event ->
+ {
+ progressBar.setIndeterminate(checkBox.isSelected());
+ progressBar.setStringPainted(!progressBar.isIndeterminate());
+ });
+ panel.add(checkBox);
+ add(new JScrollPane(textArea), BorderLayout.CENTER);
+ add(panel, BorderLayout.SOUTH);
+
+ // set up the button action
+
+ startButton.addActionListener(event ->
+ {
+ startButton.setEnabled(false);
+ activity = new SimulatedActivity(MAX);
+ activity.execute();
+ });
+ pack();
+ }
+
+ class SimulatedActivity extends SwingWorker
+ {
+ private int current;
+ private int target;
+
+ /**
+ * Constructs the simulated activity that increments a counter from 0 to a
+ * given target.
+ * @param t the target value of the counter.
+ */
+ public SimulatedActivity(int t)
+ {
+ current = 0;
+ target = t;
+ }
+
+ protected Void doInBackground() throws Exception
+ {
+ try
+ {
+ while (current < target)
+ {
+ Thread.sleep(100);
+ current++;
+ publish(current);
+ }
+ }
+ catch (InterruptedException e)
+ {
+ }
+ return null;
+ }
+
+ protected void process(List chunks)
+ {
+ for (Integer chunk : chunks)
+ {
+ textArea.append(chunk + "\n");
+ progressBar.setValue(chunk);
+ }
+ }
+
+ protected void done()
+ {
+ startButton.setEnabled(true);
+ }
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/progressBar/ProgressBarTest.java b/corejava第10版/v2ch10/progressBar/ProgressBarTest.java
new file mode 100644
index 0000000..e77066e
--- /dev/null
+++ b/corejava第10版/v2ch10/progressBar/ProgressBarTest.java
@@ -0,0 +1,23 @@
+package progressBar;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates the use of a progress bar to monitor the progress of a thread.
+ * @version 1.05 2012-05-10
+ * @author Cay Horstmann
+ */
+public class ProgressBarTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new ProgressBarFrame();
+ frame.setTitle("ProgressBarTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
diff --git a/corejava第10版/v2ch10/progressMonitor/ProgressMonitorFrame.java b/corejava第10版/v2ch10/progressMonitor/ProgressMonitorFrame.java
new file mode 100644
index 0000000..81cc178
--- /dev/null
+++ b/corejava第10版/v2ch10/progressMonitor/ProgressMonitorFrame.java
@@ -0,0 +1,108 @@
+package progressMonitor;
+
+import java.awt.*;
+
+import javax.swing.*;
+
+/**
+ * A frame that contains a button to launch a simulated activity and a text area for the activity
+ * output.
+ */
+class ProgressMonitorFrame extends JFrame
+{
+ public static final int TEXT_ROWS = 10;
+ public static final int TEXT_COLUMNS = 40;
+
+ private Timer cancelMonitor;
+ private JButton startButton;
+ private ProgressMonitor progressDialog;
+ private JTextArea textArea;
+ private SimulatedActivity activity;
+
+ public ProgressMonitorFrame()
+ {
+ // this text area holds the activity output
+ textArea = new JTextArea(TEXT_ROWS, TEXT_COLUMNS);
+
+ // set up a button panel
+ JPanel panel = new JPanel();
+ startButton = new JButton("Start");
+ panel.add(startButton);
+
+ add(new JScrollPane(textArea), BorderLayout.CENTER);
+ add(panel, BorderLayout.SOUTH);
+
+ // set up the button action
+
+ startButton.addActionListener(event ->
+ {
+ startButton.setEnabled(false);
+ final int MAX = 1000;
+
+ // start activity
+ activity = new SimulatedActivity(MAX);
+ activity.execute();
+
+ // launch progress dialog
+ progressDialog = new ProgressMonitor(ProgressMonitorFrame.this,
+ "Waiting for Simulated Activity", null, 0, MAX);
+ cancelMonitor.start();
+ });
+
+ // set up the timer action
+
+ cancelMonitor = new Timer(500, event ->
+ {
+ if (progressDialog.isCanceled())
+ {
+ activity.cancel(true);
+ startButton.setEnabled(true);
+ }
+ else if (activity.isDone())
+ {
+ progressDialog.close();
+ startButton.setEnabled(true);
+ }
+ else
+ {
+ progressDialog.setProgress(activity.getProgress());
+ }
+ });
+ pack();
+ }
+
+ class SimulatedActivity extends SwingWorker
+ {
+ private int current;
+ private int target;
+
+ /**
+ * Constructs the simulated activity that increments a counter from 0 to a
+ * given target.
+ * @param t the target value of the counter.
+ */
+ public SimulatedActivity(int t)
+ {
+ current = 0;
+ target = t;
+ }
+
+ protected Void doInBackground() throws Exception
+ {
+ try
+ {
+ while (current < target)
+ {
+ Thread.sleep(100);
+ current++;
+ textArea.append(current + "\n");
+ setProgress(current);
+ }
+ }
+ catch (InterruptedException e)
+ {
+ }
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/progressMonitor/ProgressMonitorTest.java b/corejava第10版/v2ch10/progressMonitor/ProgressMonitorTest.java
new file mode 100644
index 0000000..43cf231
--- /dev/null
+++ b/corejava第10版/v2ch10/progressMonitor/ProgressMonitorTest.java
@@ -0,0 +1,23 @@
+package progressMonitor;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * A program to test a progress monitor dialog.
+ * @version 1.05 2016-05-10
+ * @author Cay Horstmann
+ */
+public class ProgressMonitorTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new ProgressMonitorFrame();
+ frame.setTitle("ProgressMonitorTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/progressMonitorInputStream/ProgressMonitorInputStreamTest.java b/corejava第10版/v2ch10/progressMonitorInputStream/ProgressMonitorInputStreamTest.java
new file mode 100644
index 0000000..72c3eba
--- /dev/null
+++ b/corejava第10版/v2ch10/progressMonitorInputStream/ProgressMonitorInputStreamTest.java
@@ -0,0 +1,23 @@
+package progressMonitorInputStream;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * A program to test a progress monitor input stream.
+ * @version 1.06 2016-05-10
+ * @author Cay Horstmann
+ */
+public class ProgressMonitorInputStreamTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new TextFrame();
+ frame.setTitle("ProgressMonitorInputStreamTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/progressMonitorInputStream/TextFrame.java b/corejava第10版/v2ch10/progressMonitorInputStream/TextFrame.java
new file mode 100644
index 0000000..a06d037
--- /dev/null
+++ b/corejava第10版/v2ch10/progressMonitorInputStream/TextFrame.java
@@ -0,0 +1,92 @@
+package progressMonitorInputStream;
+
+import java.io.*;
+import java.nio.file.*;
+import java.util.*;
+
+import javax.swing.*;
+
+/**
+ * A frame with a menu to load a text file and a text area to display its contents. The text area is
+ * constructed when the file is loaded and set as the content pane of the frame when the loading is
+ * complete. That avoids flicker during loading.
+ */
+public class TextFrame extends JFrame
+{
+ public static final int TEXT_ROWS = 10;
+ public static final int TEXT_COLUMNS = 40;
+
+ private JMenuItem openItem;
+ private JMenuItem exitItem;
+ private JTextArea textArea;
+ private JFileChooser chooser;
+
+ public TextFrame()
+ {
+ textArea = new JTextArea(TEXT_ROWS, TEXT_COLUMNS);
+ add(new JScrollPane(textArea));
+
+ chooser = new JFileChooser();
+ chooser.setCurrentDirectory(new File("."));
+
+ JMenuBar menuBar = new JMenuBar();
+ setJMenuBar(menuBar);
+ JMenu fileMenu = new JMenu("File");
+ menuBar.add(fileMenu);
+ openItem = new JMenuItem("Open");
+ openItem.addActionListener(event ->
+ {
+ try
+ {
+ openFile();
+ }
+ catch (IOException exception)
+ {
+ exception.printStackTrace();
+ }
+ });
+
+ fileMenu.add(openItem);
+ exitItem = new JMenuItem("Exit");
+ exitItem.addActionListener(event -> System.exit(0));
+ fileMenu.add(exitItem);
+ pack();
+ }
+
+ /**
+ * Prompts the user to select a file, loads the file into a text area, and sets it as the content
+ * pane of the frame.
+ */
+ public void openFile() throws IOException
+ {
+ int r = chooser.showOpenDialog(this);
+ if (r != JFileChooser.APPROVE_OPTION) return;
+ final File f = chooser.getSelectedFile();
+
+ // set up stream and reader filter sequence
+
+ InputStream fileIn = Files.newInputStream(f.toPath());
+ final ProgressMonitorInputStream progressIn = new ProgressMonitorInputStream(
+ this, "Reading " + f.getName(), fileIn);
+
+ textArea.setText("");
+
+ SwingWorker worker = new SwingWorker()
+ {
+ protected Void doInBackground() throws Exception
+ {
+ try (Scanner in = new Scanner(progressIn, "UTF-8"))
+ {
+ while (in.hasNextLine())
+ {
+ String line = in.nextLine();
+ textArea.append(line);
+ textArea.append("\n");
+ }
+ }
+ return null;
+ }
+ };
+ worker.execute();
+ }
+}
diff --git a/corejava第10版/v2ch10/spinner/PermutationSpinnerModel.java b/corejava第10版/v2ch10/spinner/PermutationSpinnerModel.java
new file mode 100644
index 0000000..b7fde5f
--- /dev/null
+++ b/corejava第10版/v2ch10/spinner/PermutationSpinnerModel.java
@@ -0,0 +1,99 @@
+package spinner;
+
+import javax.swing.*;
+
+/**
+ * A model that dynamically generates word permutations.
+ */
+public class PermutationSpinnerModel extends AbstractSpinnerModel
+{
+ private String word;
+
+ /**
+ * Constructs the model.
+ * @param w the word to permute
+ */
+ public PermutationSpinnerModel(String w)
+ {
+ word = w;
+ }
+
+ public Object getValue()
+ {
+ return word;
+ }
+
+ public void setValue(Object value)
+ {
+ if (!(value instanceof String)) throw new IllegalArgumentException();
+ word = (String) value;
+ fireStateChanged();
+ }
+
+ public Object getNextValue()
+ {
+ int[] codePoints = toCodePointArray(word);
+ for (int i = codePoints.length - 1; i > 0; i--)
+ {
+ if (codePoints[i - 1] < codePoints[i])
+ {
+ int j = codePoints.length - 1;
+ while (codePoints[i - 1] > codePoints[j])
+ j--;
+ swap(codePoints, i - 1, j);
+ reverse(codePoints, i, codePoints.length - 1);
+ return new String(codePoints, 0, codePoints.length);
+ }
+ }
+ reverse(codePoints, 0, codePoints.length - 1);
+ return new String(codePoints, 0, codePoints.length);
+ }
+
+ public Object getPreviousValue()
+ {
+ int[] codePoints = toCodePointArray(word);
+ for (int i = codePoints.length - 1; i > 0; i--)
+ {
+ if (codePoints[i - 1] > codePoints[i])
+ {
+ int j = codePoints.length - 1;
+ while (codePoints[i - 1] < codePoints[j])
+ j--;
+ swap(codePoints, i - 1, j);
+ reverse(codePoints, i, codePoints.length - 1);
+ return new String(codePoints, 0, codePoints.length);
+ }
+ }
+ reverse(codePoints, 0, codePoints.length - 1);
+ return new String(codePoints, 0, codePoints.length);
+ }
+
+ private static int[] toCodePointArray(String str)
+ {
+ int[] codePoints = new int[str.codePointCount(0, str.length())];
+ for (int i = 0, j = 0; i < str.length(); i++, j++)
+ {
+ int cp = str.codePointAt(i);
+ if (Character.isSupplementaryCodePoint(cp)) i++;
+ codePoints[j] = cp;
+ }
+ return codePoints;
+ }
+
+ private static void swap(int[] a, int i, int j)
+ {
+ int temp = a[i];
+ a[i] = a[j];
+ a[j] = temp;
+ }
+
+ private static void reverse(int[] a, int i, int j)
+ {
+ while (i < j)
+ {
+ swap(a, i, j);
+ i++;
+ j--;
+ }
+ }
+}
diff --git a/corejava第10版/v2ch10/spinner/SpinnerFrame.java b/corejava第10版/v2ch10/spinner/SpinnerFrame.java
new file mode 100644
index 0000000..a44e4b5
--- /dev/null
+++ b/corejava第10版/v2ch10/spinner/SpinnerFrame.java
@@ -0,0 +1,82 @@
+package spinner;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.text.*;
+import javax.swing.*;
+
+/**
+ * A frame with a panel that contains several spinners and a button that displays the spinner
+ * values.
+ */
+public class SpinnerFrame extends JFrame
+{
+ private JPanel mainPanel;
+ private JButton okButton;
+
+ public SpinnerFrame()
+ {
+ JPanel buttonPanel = new JPanel();
+ okButton = new JButton("Ok");
+ buttonPanel.add(okButton);
+ add(buttonPanel, BorderLayout.SOUTH);
+
+ mainPanel = new JPanel();
+ mainPanel.setLayout(new GridLayout(0, 3));
+ add(mainPanel, BorderLayout.CENTER);
+
+ JSpinner defaultSpinner = new JSpinner();
+ addRow("Default", defaultSpinner);
+
+ JSpinner boundedSpinner = new JSpinner(new SpinnerNumberModel(5, 0, 10, 0.5));
+ addRow("Bounded", boundedSpinner);
+
+ String[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment()
+ .getAvailableFontFamilyNames();
+
+ JSpinner listSpinner = new JSpinner(new SpinnerListModel(fonts));
+ addRow("List", listSpinner);
+
+ JSpinner reverseListSpinner = new JSpinner(new SpinnerListModel(fonts)
+ {
+ public Object getNextValue() { return super.getPreviousValue(); }
+ public Object getPreviousValue() { return super.getNextValue(); }
+ });
+ addRow("Reverse List", reverseListSpinner);
+
+ JSpinner dateSpinner = new JSpinner(new SpinnerDateModel());
+ addRow("Date", dateSpinner);
+
+ JSpinner betterDateSpinner = new JSpinner(new SpinnerDateModel());
+ String pattern = ((SimpleDateFormat) DateFormat.getDateInstance()).toPattern();
+ betterDateSpinner.setEditor(new JSpinner.DateEditor(betterDateSpinner, pattern));
+ addRow("Better Date", betterDateSpinner);
+
+ JSpinner timeSpinner = new JSpinner(new SpinnerDateModel());
+ pattern = ((SimpleDateFormat) DateFormat.getTimeInstance(DateFormat.SHORT)).toPattern();
+ timeSpinner.setEditor(new JSpinner.DateEditor(timeSpinner, pattern));
+ addRow("Time", timeSpinner);
+
+ JSpinner permSpinner = new JSpinner(new PermutationSpinnerModel("meat"));
+ addRow("Word permutations", permSpinner);
+ pack();
+ }
+
+ /**
+ * Adds a row to the main panel.
+ * @param labelText the label of the spinner
+ * @param spinner the sample spinner
+ */
+ public void addRow(String labelText, final JSpinner spinner)
+ {
+ mainPanel.add(new JLabel(labelText));
+ mainPanel.add(spinner);
+ final JLabel valueLabel = new JLabel();
+ mainPanel.add(valueLabel);
+ okButton.addActionListener(event ->
+ {
+ Object value = spinner.getValue();
+ valueLabel.setText(value.toString());
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/spinner/SpinnerTest.java b/corejava第10版/v2ch10/spinner/SpinnerTest.java
new file mode 100644
index 0000000..5ca85c0
--- /dev/null
+++ b/corejava第10版/v2ch10/spinner/SpinnerTest.java
@@ -0,0 +1,24 @@
+package spinner;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * A program to test spinners.
+ * @version 1.03 2016-05-10
+ * @author Cay Horstmann
+ */
+public class SpinnerTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new SpinnerFrame();
+ frame.setTitle("SpinnerTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
diff --git a/javacore第11版/corejava/v2ch11/tableRowColumn/Earth.gif b/corejava第10版/v2ch10/splitPane/Earth.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/tableRowColumn/Earth.gif
rename to corejava第10版/v2ch10/splitPane/Earth.gif
diff --git a/javacore第11版/corejava/v2ch11/tableRowColumn/Jupiter.gif b/corejava第10版/v2ch10/splitPane/Jupiter.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/tableRowColumn/Jupiter.gif
rename to corejava第10版/v2ch10/splitPane/Jupiter.gif
diff --git a/javacore第11版/corejava/v2ch11/tableRowColumn/Mars.gif b/corejava第10版/v2ch10/splitPane/Mars.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/tableRowColumn/Mars.gif
rename to corejava第10版/v2ch10/splitPane/Mars.gif
diff --git a/javacore第11版/corejava/v2ch11/tableRowColumn/Mercury.gif b/corejava第10版/v2ch10/splitPane/Mercury.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/tableRowColumn/Mercury.gif
rename to corejava第10版/v2ch10/splitPane/Mercury.gif
diff --git a/javacore第11版/corejava/v2ch11/tableRowColumn/Neptune.gif b/corejava第10版/v2ch10/splitPane/Neptune.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/tableRowColumn/Neptune.gif
rename to corejava第10版/v2ch10/splitPane/Neptune.gif
diff --git a/corejava第10版/v2ch10/splitPane/Planet.java b/corejava第10版/v2ch10/splitPane/Planet.java
new file mode 100644
index 0000000..268b7ef
--- /dev/null
+++ b/corejava第10版/v2ch10/splitPane/Planet.java
@@ -0,0 +1,51 @@
+package splitPane;
+
+import javax.swing.*;
+
+/**
+ * Describes a planet.
+ */
+public class Planet
+{
+ private String name;
+ private double radius;
+ private int moons;
+ private ImageIcon image;
+
+ /**
+ * Constructs a planet.
+ * @param n the planet name
+ * @param r the planet radius
+ * @param m the number of moons
+ */
+ public Planet(String n, double r, int m)
+ {
+ name = n;
+ radius = r;
+ moons = m;
+ image = new ImageIcon(getClass().getResource(name + ".gif"));
+ }
+
+ public String toString()
+ {
+ return name;
+ }
+
+ /**
+ * Gets a description of the planet.
+ * @return the description
+ */
+ public String getDescription()
+ {
+ return "Radius: " + radius + "\nMoons: " + moons + "\n";
+ }
+
+ /**
+ * Gets an image of the planet.
+ * @return the image
+ */
+ public ImageIcon getImage()
+ {
+ return image;
+ }
+}
diff --git a/javacore第11版/corejava/v2ch11/tableRowColumn/Pluto.gif b/corejava第10版/v2ch10/splitPane/Pluto.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/tableRowColumn/Pluto.gif
rename to corejava第10版/v2ch10/splitPane/Pluto.gif
diff --git a/javacore第11版/corejava/v2ch11/tableRowColumn/Saturn.gif b/corejava第10版/v2ch10/splitPane/Saturn.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/tableRowColumn/Saturn.gif
rename to corejava第10版/v2ch10/splitPane/Saturn.gif
diff --git a/corejava第10版/v2ch10/splitPane/SplitPaneFrame.java b/corejava第10版/v2ch10/splitPane/SplitPaneFrame.java
new file mode 100644
index 0000000..bb33aef
--- /dev/null
+++ b/corejava第10版/v2ch10/splitPane/SplitPaneFrame.java
@@ -0,0 +1,53 @@
+package splitPane;
+
+import java.awt.*;
+
+import javax.swing.*;
+
+/**
+ * This frame consists of two nested split panes to demonstrate planet images and data.
+ */
+class SplitPaneFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 300;
+
+ private Planet[] planets = { new Planet("Mercury", 2440, 0), new Planet("Venus", 6052, 0),
+ new Planet("Earth", 6378, 1), new Planet("Mars", 3397, 2),
+ new Planet("Jupiter", 71492, 16), new Planet("Saturn", 60268, 18),
+ new Planet("Uranus", 25559, 17), new Planet("Neptune", 24766, 8),
+ new Planet("Pluto", 1137, 1), };
+
+ public SplitPaneFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ // set up components for planet names, images, descriptions
+
+ final JList planetList = new JList<>(planets);
+ final JLabel planetImage = new JLabel();
+ final JTextArea planetDescription = new JTextArea();
+
+ planetList.addListSelectionListener(event ->
+ {
+ Planet value = (Planet) planetList.getSelectedValue();
+
+ // update image and description
+
+ planetImage.setIcon(value.getImage());
+ planetDescription.setText(value.getDescription());
+ });
+
+ // set up split panes
+
+ JSplitPane innerPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, planetList, planetImage);
+
+ innerPane.setContinuousLayout(true);
+ innerPane.setOneTouchExpandable(true);
+
+ JSplitPane outerPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, innerPane,
+ planetDescription);
+
+ add(outerPane, BorderLayout.CENTER);
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/splitPane/SplitPaneTest.java b/corejava第10版/v2ch10/splitPane/SplitPaneTest.java
new file mode 100644
index 0000000..1df0548
--- /dev/null
+++ b/corejava第10版/v2ch10/splitPane/SplitPaneTest.java
@@ -0,0 +1,23 @@
+package splitPane;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates the split pane component organizer.
+ * @version 1.04 2016-05-10
+ * @author Cay Horstmann
+ */
+public class SplitPaneTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new SplitPaneFrame();
+ frame.setTitle("SplitPaneTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v2ch11/tableRowColumn/Uranus.gif b/corejava第10版/v2ch10/splitPane/Uranus.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/tableRowColumn/Uranus.gif
rename to corejava第10版/v2ch10/splitPane/Uranus.gif
diff --git a/javacore第11版/corejava/v2ch11/tableRowColumn/Venus.gif b/corejava第10版/v2ch10/splitPane/Venus.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/tableRowColumn/Venus.gif
rename to corejava第10版/v2ch10/splitPane/Venus.gif
diff --git a/corejava第10版/v2ch10/tabbedPane/Earth.gif b/corejava第10版/v2ch10/tabbedPane/Earth.gif
new file mode 100644
index 0000000..5982457
Binary files /dev/null and b/corejava第10版/v2ch10/tabbedPane/Earth.gif differ
diff --git a/corejava第10版/v2ch10/tabbedPane/Jupiter.gif b/corejava第10版/v2ch10/tabbedPane/Jupiter.gif
new file mode 100644
index 0000000..32d271d
Binary files /dev/null and b/corejava第10版/v2ch10/tabbedPane/Jupiter.gif differ
diff --git a/corejava第10版/v2ch10/tabbedPane/Mars.gif b/corejava第10版/v2ch10/tabbedPane/Mars.gif
new file mode 100644
index 0000000..234d36f
Binary files /dev/null and b/corejava第10版/v2ch10/tabbedPane/Mars.gif differ
diff --git a/corejava第10版/v2ch10/tabbedPane/Mercury.gif b/corejava第10版/v2ch10/tabbedPane/Mercury.gif
new file mode 100644
index 0000000..9fd78a5
Binary files /dev/null and b/corejava第10版/v2ch10/tabbedPane/Mercury.gif differ
diff --git a/corejava第10版/v2ch10/tabbedPane/Neptune.gif b/corejava第10版/v2ch10/tabbedPane/Neptune.gif
new file mode 100644
index 0000000..33b18f2
Binary files /dev/null and b/corejava第10版/v2ch10/tabbedPane/Neptune.gif differ
diff --git a/corejava第10版/v2ch10/tabbedPane/Pluto.gif b/corejava第10版/v2ch10/tabbedPane/Pluto.gif
new file mode 100644
index 0000000..3909638
Binary files /dev/null and b/corejava第10版/v2ch10/tabbedPane/Pluto.gif differ
diff --git a/corejava第10版/v2ch10/tabbedPane/Saturn.gif b/corejava第10版/v2ch10/tabbedPane/Saturn.gif
new file mode 100644
index 0000000..b4c6144
Binary files /dev/null and b/corejava第10版/v2ch10/tabbedPane/Saturn.gif differ
diff --git a/corejava第10版/v2ch10/tabbedPane/TabbedPaneFrame.java b/corejava第10版/v2ch10/tabbedPane/TabbedPaneFrame.java
new file mode 100644
index 0000000..69d8366
--- /dev/null
+++ b/corejava第10版/v2ch10/tabbedPane/TabbedPaneFrame.java
@@ -0,0 +1,93 @@
+package tabbedPane;
+
+import java.awt.*;
+
+import javax.swing.*;
+
+/**
+ * This frame shows a tabbed pane and radio buttons to switch between wrapped and scrolling tab
+ * layout.
+ */
+public class TabbedPaneFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 400;
+ private static final int DEFAULT_HEIGHT = 300;
+
+ private JTabbedPane tabbedPane;
+
+ public TabbedPaneFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ tabbedPane = new JTabbedPane();
+ // we set the components to null and delay their loading until the tab is shown
+ // for the first time
+
+ ImageIcon icon = new ImageIcon(getClass().getResource("yellow-ball.gif"));
+
+ tabbedPane.addTab("Mercury", icon, null);
+ tabbedPane.addTab("Venus", icon, null);
+ tabbedPane.addTab("Earth", icon, null);
+ tabbedPane.addTab("Mars", icon, null);
+ tabbedPane.addTab("Jupiter", icon, null);
+ tabbedPane.addTab("Saturn", icon, null);
+ tabbedPane.addTab("Uranus", icon, null);
+ tabbedPane.addTab("Neptune", icon, null);
+ tabbedPane.addTab("Pluto", null, null);
+
+ final int plutoIndex = tabbedPane.indexOfTab("Pluto");
+ JPanel plutoPanel = new JPanel();
+ plutoPanel.add(new JLabel("Pluto", icon, SwingConstants.LEADING));
+ JToggleButton plutoCheckBox = new JCheckBox();
+ plutoCheckBox.addActionListener(event -> tabbedPane.remove(plutoIndex));
+ plutoPanel.add(plutoCheckBox);
+ tabbedPane.setTabComponentAt(plutoIndex, plutoPanel);
+
+ add(tabbedPane, "Center");
+
+ tabbedPane.addChangeListener(event ->
+ {
+ // check if this tab still has a null component
+
+ if (tabbedPane.getSelectedComponent() == null)
+ {
+ // set the component to the image icon
+
+ int n = tabbedPane.getSelectedIndex();
+ loadTab(n);
+ }
+ });
+
+ loadTab(0);
+
+ JPanel buttonPanel = new JPanel();
+ ButtonGroup buttonGroup = new ButtonGroup();
+ JRadioButton wrapButton = new JRadioButton("Wrap tabs");
+ wrapButton.addActionListener(event ->
+ tabbedPane.setTabLayoutPolicy(JTabbedPane.WRAP_TAB_LAYOUT));
+ buttonPanel.add(wrapButton);
+ buttonGroup.add(wrapButton);
+ wrapButton.setSelected(true);
+ JRadioButton scrollButton = new JRadioButton("Scroll tabs");
+ scrollButton.addActionListener(event ->
+ tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT));
+ buttonPanel.add(scrollButton);
+ buttonGroup.add(scrollButton);
+ add(buttonPanel, BorderLayout.SOUTH);
+ }
+
+ /**
+ * Loads the tab with the given index.
+ * @param n the index of the tab to load
+ */
+ private void loadTab(int n)
+ {
+ String title = tabbedPane.getTitleAt(n);
+ ImageIcon planetIcon = new ImageIcon(getClass().getResource(title + ".gif"));
+ tabbedPane.setComponentAt(n, new JLabel(planetIcon));
+
+ // indicate that this tab has been visited--just for fun
+
+ tabbedPane.setIconAt(n, new ImageIcon(getClass().getResource("red-ball.gif")));
+ }
+}
diff --git a/corejava第10版/v2ch10/tabbedPane/TabbedPaneTest.java b/corejava第10版/v2ch10/tabbedPane/TabbedPaneTest.java
new file mode 100644
index 0000000..b322ba6
--- /dev/null
+++ b/corejava第10版/v2ch10/tabbedPane/TabbedPaneTest.java
@@ -0,0 +1,24 @@
+package tabbedPane;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates the tabbed pane component organizer.
+ * @version 1.04 2016-05-10
+ * @author Cay Horstmann
+ */
+public class TabbedPaneTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new TabbedPaneFrame();
+ frame.setTitle("TabbedPaneTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
diff --git a/corejava第10版/v2ch10/tabbedPane/Uranus.gif b/corejava第10版/v2ch10/tabbedPane/Uranus.gif
new file mode 100644
index 0000000..e9baa5d
Binary files /dev/null and b/corejava第10版/v2ch10/tabbedPane/Uranus.gif differ
diff --git a/corejava第10版/v2ch10/tabbedPane/Venus.gif b/corejava第10版/v2ch10/tabbedPane/Venus.gif
new file mode 100644
index 0000000..8552313
Binary files /dev/null and b/corejava第10版/v2ch10/tabbedPane/Venus.gif differ
diff --git a/javacore第11版/corejava/v2ch11/treeRender/red-ball.gif b/corejava第10版/v2ch10/tabbedPane/red-ball.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/treeRender/red-ball.gif
rename to corejava第10版/v2ch10/tabbedPane/red-ball.gif
diff --git a/corejava第10版/v2ch10/tabbedPane/yellow-ball.gif b/corejava第10版/v2ch10/tabbedPane/yellow-ball.gif
new file mode 100644
index 0000000..2b8c0bb
Binary files /dev/null and b/corejava第10版/v2ch10/tabbedPane/yellow-ball.gif differ
diff --git a/corejava第10版/v2ch10/table/TableTest.java b/corejava第10版/v2ch10/table/TableTest.java
new file mode 100644
index 0000000..c636fc1
--- /dev/null
+++ b/corejava第10版/v2ch10/table/TableTest.java
@@ -0,0 +1,56 @@
+package table;
+
+import java.awt.*;
+import java.awt.print.*;
+
+import javax.swing.*;
+
+/**
+ * This program demonstrates how to show a simple table.
+ * @version 1.13 2016-05-10
+ * @author Cay Horstmann
+ */
+public class TableTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new PlanetTableFrame();
+ frame.setTitle("TableTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * This frame contains a table of planet data.
+ */
+class PlanetTableFrame extends JFrame
+{
+ private String[] columnNames = { "Planet", "Radius", "Moons", "Gaseous", "Color" };
+ private Object[][] cells = { { "Mercury", 2440.0, 0, false, Color.YELLOW },
+ { "Venus", 6052.0, 0, false, Color.YELLOW }, { "Earth", 6378.0, 1, false, Color.BLUE },
+ { "Mars", 3397.0, 2, false, Color.RED }, { "Jupiter", 71492.0, 16, true, Color.ORANGE },
+ { "Saturn", 60268.0, 18, true, Color.ORANGE },
+ { "Uranus", 25559.0, 17, true, Color.BLUE }, { "Neptune", 24766.0, 8, true, Color.BLUE },
+ { "Pluto", 1137.0, 1, false, Color.BLACK } };
+
+ public PlanetTableFrame()
+ {
+ final JTable table = new JTable(cells, columnNames);
+ table.setAutoCreateRowSorter(true);
+ add(new JScrollPane(table), BorderLayout.CENTER);
+ JButton printButton = new JButton("Print");
+ printButton.addActionListener(event ->
+ {
+ try { table.print(); }
+ catch (SecurityException | PrinterException ex) { ex.printStackTrace(); }
+ });
+ JPanel buttonPanel = new JPanel();
+ buttonPanel.add(printButton);
+ add(buttonPanel, BorderLayout.SOUTH);
+ pack();
+ }
+}
diff --git a/corejava第10版/v2ch10/tableCellRender/ColorTableCellEditor.java b/corejava第10版/v2ch10/tableCellRender/ColorTableCellEditor.java
new file mode 100644
index 0000000..37fadc9
--- /dev/null
+++ b/corejava第10版/v2ch10/tableCellRender/ColorTableCellEditor.java
@@ -0,0 +1,69 @@
+package tableCellRender;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.beans.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.table.*;
+
+/**
+ * This editor pops up a color dialog to edit a cell value.
+ */
+public class ColorTableCellEditor extends AbstractCellEditor implements TableCellEditor
+{
+ private JColorChooser colorChooser;
+ private JDialog colorDialog;
+ private JPanel panel;
+
+ public ColorTableCellEditor()
+ {
+ panel = new JPanel();
+ // prepare color dialog
+
+ colorChooser = new JColorChooser();
+ colorDialog = JColorChooser.createDialog(null, "Planet Color", false, colorChooser,
+ EventHandler.create(ActionListener.class, this, "stopCellEditing"),
+ EventHandler.create(ActionListener.class, this, "cancelCellEditing"));
+ }
+
+ public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected,
+ int row, int column)
+ {
+ // this is where we get the current Color value. We store it in the dialog in case the user.
+ // starts editing
+ colorChooser.setColor((Color) value);
+ return panel;
+ }
+
+ public boolean shouldSelectCell(EventObject anEvent)
+ {
+ // start editing
+ colorDialog.setVisible(true);
+
+ // tell caller it is ok to select this cell
+ return true;
+ }
+
+ public void cancelCellEditing()
+ {
+ // editing is canceled--hide dialog
+ colorDialog.setVisible(false);
+ super.cancelCellEditing();
+ }
+
+ public boolean stopCellEditing()
+ {
+ // editing is complete--hide dialog
+ colorDialog.setVisible(false);
+ super.stopCellEditing();
+
+ // tell caller is is ok to use color value
+ return true;
+ }
+
+ public Object getCellEditorValue()
+ {
+ return colorChooser.getColor();
+ }
+}
diff --git a/corejava第10版/v2ch10/tableCellRender/ColorTableCellRenderer.java b/corejava第10版/v2ch10/tableCellRender/ColorTableCellRenderer.java
new file mode 100644
index 0000000..c2e608d
--- /dev/null
+++ b/corejava第10版/v2ch10/tableCellRender/ColorTableCellRenderer.java
@@ -0,0 +1,20 @@
+package tableCellRender;
+
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.table.*;
+
+/**
+ * This renderer renders a color value as a panel with the given color.
+ */
+public class ColorTableCellRenderer extends JPanel implements TableCellRenderer
+{
+ public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
+ boolean hasFocus, int row, int column)
+ {
+ setBackground((Color) value);
+ if (hasFocus) setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
+ else setBorder(null);
+ return this;
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/tableCellRender/Earth.gif b/corejava第10版/v2ch10/tableCellRender/Earth.gif
new file mode 100644
index 0000000..5982457
Binary files /dev/null and b/corejava第10版/v2ch10/tableCellRender/Earth.gif differ
diff --git a/corejava第10版/v2ch10/tableCellRender/Jupiter.gif b/corejava第10版/v2ch10/tableCellRender/Jupiter.gif
new file mode 100644
index 0000000..32d271d
Binary files /dev/null and b/corejava第10版/v2ch10/tableCellRender/Jupiter.gif differ
diff --git a/corejava第10版/v2ch10/tableCellRender/Mars.gif b/corejava第10版/v2ch10/tableCellRender/Mars.gif
new file mode 100644
index 0000000..234d36f
Binary files /dev/null and b/corejava第10版/v2ch10/tableCellRender/Mars.gif differ
diff --git a/corejava第10版/v2ch10/tableCellRender/Mercury.gif b/corejava第10版/v2ch10/tableCellRender/Mercury.gif
new file mode 100644
index 0000000..9fd78a5
Binary files /dev/null and b/corejava第10版/v2ch10/tableCellRender/Mercury.gif differ
diff --git a/javacore第11版/corejava/v2ch11/tableCellRender/Moons.gif b/corejava第10版/v2ch10/tableCellRender/Moons.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/tableCellRender/Moons.gif
rename to corejava第10版/v2ch10/tableCellRender/Moons.gif
diff --git a/corejava第10版/v2ch10/tableCellRender/Neptune.gif b/corejava第10版/v2ch10/tableCellRender/Neptune.gif
new file mode 100644
index 0000000..33b18f2
Binary files /dev/null and b/corejava第10版/v2ch10/tableCellRender/Neptune.gif differ
diff --git a/corejava第10版/v2ch10/tableCellRender/PlanetTableModel.java b/corejava第10版/v2ch10/tableCellRender/PlanetTableModel.java
new file mode 100644
index 0000000..b22f2c4
--- /dev/null
+++ b/corejava第10版/v2ch10/tableCellRender/PlanetTableModel.java
@@ -0,0 +1,74 @@
+package tableCellRender;
+
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.table.*;
+
+/**
+ * The planet table model specifies the values, rendering and editing properties for the planet
+ * data.
+ */
+public class PlanetTableModel extends AbstractTableModel
+{
+ public static final int PLANET_COLUMN = 0;
+ public static final int MOONS_COLUMN = 2;
+ public static final int GASEOUS_COLUMN = 3;
+ public static final int COLOR_COLUMN = 4;
+
+ private Object[][] cells = {
+ { "Mercury", 2440.0, 0, false, Color.YELLOW,
+ new ImageIcon(getClass().getResource("Mercury.gif")) },
+ { "Venus", 6052.0, 0, false, Color.YELLOW,
+ new ImageIcon(getClass().getResource("Venus.gif")) },
+ { "Earth", 6378.0, 1, false, Color.BLUE,
+ new ImageIcon(getClass().getResource("Earth.gif")) },
+ { "Mars", 3397.0, 2, false, Color.RED,
+ new ImageIcon(getClass().getResource("Mars.gif")) },
+ { "Jupiter", 71492.0, 16, true, Color.ORANGE,
+ new ImageIcon(getClass().getResource("Jupiter.gif")) },
+ { "Saturn", 60268.0, 18, true, Color.ORANGE,
+ new ImageIcon(getClass().getResource("Saturn.gif")) },
+ { "Uranus", 25559.0, 17, true, Color.BLUE,
+ new ImageIcon(getClass().getResource("Uranus.gif")) },
+ { "Neptune", 24766.0, 8, true, Color.BLUE,
+ new ImageIcon(getClass().getResource("Neptune.gif")) },
+ { "Pluto", 1137.0, 1, false, Color.BLACK,
+ new ImageIcon(getClass().getResource("Pluto.gif")) } };
+
+ private String[] columnNames = { "Planet", "Radius", "Moons", "Gaseous", "Color", "Image" };
+
+ public String getColumnName(int c)
+ {
+ return columnNames[c];
+ }
+
+ public Class> getColumnClass(int c)
+ {
+ return cells[0][c].getClass();
+ }
+
+ public int getColumnCount()
+ {
+ return cells[0].length;
+ }
+
+ public int getRowCount()
+ {
+ return cells.length;
+ }
+
+ public Object getValueAt(int r, int c)
+ {
+ return cells[r][c];
+ }
+
+ public void setValueAt(Object obj, int r, int c)
+ {
+ cells[r][c] = obj;
+ }
+
+ public boolean isCellEditable(int r, int c)
+ {
+ return c == PLANET_COLUMN || c == MOONS_COLUMN || c == GASEOUS_COLUMN || c == COLOR_COLUMN;
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/tableCellRender/Pluto.gif b/corejava第10版/v2ch10/tableCellRender/Pluto.gif
new file mode 100644
index 0000000..3909638
Binary files /dev/null and b/corejava第10版/v2ch10/tableCellRender/Pluto.gif differ
diff --git a/corejava第10版/v2ch10/tableCellRender/Saturn.gif b/corejava第10版/v2ch10/tableCellRender/Saturn.gif
new file mode 100644
index 0000000..b4c6144
Binary files /dev/null and b/corejava第10版/v2ch10/tableCellRender/Saturn.gif differ
diff --git a/corejava第10版/v2ch10/tableCellRender/TableCellRenderFrame.java b/corejava第10版/v2ch10/tableCellRender/TableCellRenderFrame.java
new file mode 100644
index 0000000..8f6009c
--- /dev/null
+++ b/corejava第10版/v2ch10/tableCellRender/TableCellRenderFrame.java
@@ -0,0 +1,44 @@
+package tableCellRender;
+
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.table.*;
+
+/**
+ * This frame contains a table of planet data.
+ */
+public class TableCellRenderFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 600;
+ private static final int DEFAULT_HEIGHT = 400;
+
+ public TableCellRenderFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ TableModel model = new PlanetTableModel();
+ JTable table = new JTable(model);
+ table.setRowSelectionAllowed(false);
+
+ // set up renderers and editors
+
+ table.setDefaultRenderer(Color.class, new ColorTableCellRenderer());
+ table.setDefaultEditor(Color.class, new ColorTableCellEditor());
+
+ JComboBox moonCombo = new JComboBox<>();
+ for (int i = 0; i <= 20; i++)
+ moonCombo.addItem(i);
+
+ TableColumnModel columnModel = table.getColumnModel();
+ TableColumn moonColumn = columnModel.getColumn(PlanetTableModel.MOONS_COLUMN);
+ moonColumn.setCellEditor(new DefaultCellEditor(moonCombo));
+ moonColumn.setHeaderRenderer(table.getDefaultRenderer(ImageIcon.class));
+ moonColumn.setHeaderValue(new ImageIcon(getClass().getResource("Moons.gif")));
+
+ // show table
+
+ table.setRowHeight(100);
+ add(new JScrollPane(table), BorderLayout.CENTER);
+ }
+}
+
diff --git a/corejava第10版/v2ch10/tableCellRender/TableCellRenderTest.java b/corejava第10版/v2ch10/tableCellRender/TableCellRenderTest.java
new file mode 100644
index 0000000..8a151d6
--- /dev/null
+++ b/corejava第10版/v2ch10/tableCellRender/TableCellRenderTest.java
@@ -0,0 +1,24 @@
+package tableCellRender;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates cell rendering and editing in a table.
+ * @version 1.04 2016-05-10
+ * @author Cay Horstmann
+ */
+public class TableCellRenderTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+
+ JFrame frame = new TableCellRenderFrame();
+ frame.setTitle("TableCellRenderTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/tableCellRender/Uranus.gif b/corejava第10版/v2ch10/tableCellRender/Uranus.gif
new file mode 100644
index 0000000..e9baa5d
Binary files /dev/null and b/corejava第10版/v2ch10/tableCellRender/Uranus.gif differ
diff --git a/corejava第10版/v2ch10/tableCellRender/Venus.gif b/corejava第10版/v2ch10/tableCellRender/Venus.gif
new file mode 100644
index 0000000..8552313
Binary files /dev/null and b/corejava第10版/v2ch10/tableCellRender/Venus.gif differ
diff --git a/corejava第10版/v2ch10/tableModel/InvestmentTable.java b/corejava第10版/v2ch10/tableModel/InvestmentTable.java
new file mode 100644
index 0000000..5a8b5bd
--- /dev/null
+++ b/corejava第10版/v2ch10/tableModel/InvestmentTable.java
@@ -0,0 +1,89 @@
+package tableModel;
+
+import java.awt.*;
+
+import javax.swing.*;
+import javax.swing.table.*;
+
+/**
+ * This program shows how to build a table from a table model.
+ * @version 1.03 2006-05-10
+ * @author Cay Horstmann
+ */
+public class InvestmentTable
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new InvestmentTableFrame();
+ frame.setTitle("InvestmentTable");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * This frame contains the investment table.
+ */
+class InvestmentTableFrame extends JFrame
+{
+ public InvestmentTableFrame()
+ {
+ TableModel model = new InvestmentTableModel(30, 5, 10);
+ JTable table = new JTable(model);
+ add(new JScrollPane(table));
+ pack();
+ }
+
+}
+
+/**
+ * This table model computes the cell entries each time they are requested. The table contents shows
+ * the growth of an investment for a number of years under different interest rates.
+ */
+class InvestmentTableModel extends AbstractTableModel
+{
+ private static double INITIAL_BALANCE = 100000.0;
+
+ private int years;
+ private int minRate;
+ private int maxRate;
+
+ /**
+ * Constructs an investment table model.
+ * @param y the number of years
+ * @param r1 the lowest interest rate to tabulate
+ * @param r2 the highest interest rate to tabulate
+ */
+ public InvestmentTableModel(int y, int r1, int r2)
+ {
+ years = y;
+ minRate = r1;
+ maxRate = r2;
+ }
+
+ public int getRowCount()
+ {
+ return years;
+ }
+
+ public int getColumnCount()
+ {
+ return maxRate - minRate + 1;
+ }
+
+ public Object getValueAt(int r, int c)
+ {
+ double rate = (c + minRate) / 100.0;
+ int nperiods = r;
+ double futureBalance = INITIAL_BALANCE * Math.pow(1 + rate, nperiods);
+ return String.format("%.2f", futureBalance);
+ }
+
+ public String getColumnName(int c)
+ {
+ return (c + minRate) + "%";
+ }
+}
diff --git a/corejava第10版/v2ch10/tableRowColumn/Earth.gif b/corejava第10版/v2ch10/tableRowColumn/Earth.gif
new file mode 100644
index 0000000..5982457
Binary files /dev/null and b/corejava第10版/v2ch10/tableRowColumn/Earth.gif differ
diff --git a/corejava第10版/v2ch10/tableRowColumn/Jupiter.gif b/corejava第10版/v2ch10/tableRowColumn/Jupiter.gif
new file mode 100644
index 0000000..32d271d
Binary files /dev/null and b/corejava第10版/v2ch10/tableRowColumn/Jupiter.gif differ
diff --git a/corejava第10版/v2ch10/tableRowColumn/Mars.gif b/corejava第10版/v2ch10/tableRowColumn/Mars.gif
new file mode 100644
index 0000000..234d36f
Binary files /dev/null and b/corejava第10版/v2ch10/tableRowColumn/Mars.gif differ
diff --git a/corejava第10版/v2ch10/tableRowColumn/Mercury.gif b/corejava第10版/v2ch10/tableRowColumn/Mercury.gif
new file mode 100644
index 0000000..9fd78a5
Binary files /dev/null and b/corejava第10版/v2ch10/tableRowColumn/Mercury.gif differ
diff --git a/corejava第10版/v2ch10/tableRowColumn/Neptune.gif b/corejava第10版/v2ch10/tableRowColumn/Neptune.gif
new file mode 100644
index 0000000..33b18f2
Binary files /dev/null and b/corejava第10版/v2ch10/tableRowColumn/Neptune.gif differ
diff --git a/corejava第10版/v2ch10/tableRowColumn/PlanetTableFrame.java b/corejava第10版/v2ch10/tableRowColumn/PlanetTableFrame.java
new file mode 100644
index 0000000..a55785b
--- /dev/null
+++ b/corejava第10版/v2ch10/tableRowColumn/PlanetTableFrame.java
@@ -0,0 +1,194 @@
+package tableRowColumn;
+
+import java.awt.*;
+import java.util.*;
+
+import javax.swing.*;
+import javax.swing.table.*;
+
+/**
+ * This frame contains a table of planet data.
+ */
+public class PlanetTableFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 600;
+ private static final int DEFAULT_HEIGHT = 500;
+
+ public static final int COLOR_COLUMN = 4;
+ public static final int IMAGE_COLUMN = 5;
+
+ private JTable table;
+ private HashSet removedRowIndices;
+ private ArrayList removedColumns;
+ private JCheckBoxMenuItem rowsItem;
+ private JCheckBoxMenuItem columnsItem;
+ private JCheckBoxMenuItem cellsItem;
+
+ private String[] columnNames = { "Planet", "Radius", "Moons", "Gaseous", "Color", "Image" };
+
+ private Object[][] cells = {
+ { "Mercury", 2440.0, 0, false, Color.YELLOW,
+ new ImageIcon(getClass().getResource("Mercury.gif")) },
+ { "Venus", 6052.0, 0, false, Color.YELLOW,
+ new ImageIcon(getClass().getResource("Venus.gif")) },
+ { "Earth", 6378.0, 1, false, Color.BLUE,
+ new ImageIcon(getClass().getResource("Earth.gif")) },
+ { "Mars", 3397.0, 2, false, Color.RED,
+ new ImageIcon(getClass().getResource("Mars.gif")) },
+ { "Jupiter", 71492.0, 16, true, Color.ORANGE,
+ new ImageIcon(getClass().getResource("Jupiter.gif")) },
+ { "Saturn", 60268.0, 18, true, Color.ORANGE,
+ new ImageIcon(getClass().getResource("Saturn.gif")) },
+ { "Uranus", 25559.0, 17, true, Color.BLUE,
+ new ImageIcon(getClass().getResource("Uranus.gif")) },
+ { "Neptune", 24766.0, 8, true, Color.BLUE,
+ new ImageIcon(getClass().getResource("Neptune.gif")) },
+ { "Pluto", 1137.0, 1, false, Color.BLACK,
+ new ImageIcon(getClass().getResource("Pluto.gif")) } };
+
+ public PlanetTableFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ TableModel model = new DefaultTableModel(cells, columnNames)
+ {
+ public Class> getColumnClass(int c)
+ {
+ return cells[0][c].getClass();
+ }
+ };
+
+ table = new JTable(model);
+
+ table.setRowHeight(100);
+ table.getColumnModel().getColumn(COLOR_COLUMN).setMinWidth(250);
+ table.getColumnModel().getColumn(IMAGE_COLUMN).setMinWidth(100);
+
+ final TableRowSorter sorter = new TableRowSorter<>(model);
+ table.setRowSorter(sorter);
+ sorter.setComparator(COLOR_COLUMN, Comparator.comparing(Color::getBlue)
+ .thenComparing(Color::getGreen).thenComparing(Color::getRed));
+ sorter.setSortable(IMAGE_COLUMN, false);
+ add(new JScrollPane(table), BorderLayout.CENTER);
+
+ removedRowIndices = new HashSet<>();
+ removedColumns = new ArrayList<>();
+
+ final RowFilter filter = new RowFilter()
+ {
+ public boolean include(Entry extends TableModel, ? extends Integer> entry)
+ {
+ return !removedRowIndices.contains(entry.getIdentifier());
+ }
+ };
+
+ // create menu
+
+ JMenuBar menuBar = new JMenuBar();
+ setJMenuBar(menuBar);
+
+ JMenu selectionMenu = new JMenu("Selection");
+ menuBar.add(selectionMenu);
+
+ rowsItem = new JCheckBoxMenuItem("Rows");
+ columnsItem = new JCheckBoxMenuItem("Columns");
+ cellsItem = new JCheckBoxMenuItem("Cells");
+
+ rowsItem.setSelected(table.getRowSelectionAllowed());
+ columnsItem.setSelected(table.getColumnSelectionAllowed());
+ cellsItem.setSelected(table.getCellSelectionEnabled());
+
+ rowsItem.addActionListener(event ->
+ {
+ table.clearSelection();
+ table.setRowSelectionAllowed(rowsItem.isSelected());
+ updateCheckboxMenuItems();
+ });
+ selectionMenu.add(rowsItem);
+
+ columnsItem.addActionListener(event ->
+ {
+ table.clearSelection();
+ table.setColumnSelectionAllowed(columnsItem.isSelected());
+ updateCheckboxMenuItems();
+ });
+ selectionMenu.add(columnsItem);
+
+ cellsItem.addActionListener(event ->
+ {
+ table.clearSelection();
+ table.setCellSelectionEnabled(cellsItem.isSelected());
+ updateCheckboxMenuItems();
+ });
+ selectionMenu.add(cellsItem);
+
+ JMenu tableMenu = new JMenu("Edit");
+ menuBar.add(tableMenu);
+
+ JMenuItem hideColumnsItem = new JMenuItem("Hide Columns");
+ hideColumnsItem.addActionListener(event ->
+ {
+ int[] selected = table.getSelectedColumns();
+ TableColumnModel columnModel = table.getColumnModel();
+
+ // remove columns from view, starting at the last
+ // index so that column numbers aren't affected
+
+ for (int i = selected.length - 1; i >= 0; i--)
+ {
+ TableColumn column = columnModel.getColumn(selected[i]);
+ table.removeColumn(column);
+
+ // store removed columns for "show columns" command
+
+ removedColumns.add(column);
+ }
+ });
+ tableMenu.add(hideColumnsItem);
+
+ JMenuItem showColumnsItem = new JMenuItem("Show Columns");
+ showColumnsItem.addActionListener(event ->
+ {
+ // restore all removed columns
+ for (TableColumn tc : removedColumns)
+ table.addColumn(tc);
+ removedColumns.clear();
+ });
+ tableMenu.add(showColumnsItem);
+
+ JMenuItem hideRowsItem = new JMenuItem("Hide Rows");
+ hideRowsItem.addActionListener(event ->
+ {
+ int[] selected = table.getSelectedRows();
+ for (int i : selected)
+ removedRowIndices.add(table.convertRowIndexToModel(i));
+ sorter.setRowFilter(filter);
+ });
+ tableMenu.add(hideRowsItem);
+
+ JMenuItem showRowsItem = new JMenuItem("Show Rows");
+ showRowsItem.addActionListener(event ->
+ {
+ removedRowIndices.clear();
+ sorter.setRowFilter(filter);
+ });
+ tableMenu.add(showRowsItem);
+
+ JMenuItem printSelectionItem = new JMenuItem("Print Selection");
+ printSelectionItem.addActionListener(event ->
+ {
+ int[] selected = table.getSelectedRows();
+ System.out.println("Selected rows: " + Arrays.toString(selected));
+ selected = table.getSelectedColumns();
+ System.out.println("Selected columns: " + Arrays.toString(selected));
+ });
+ tableMenu.add(printSelectionItem);
+ }
+
+ private void updateCheckboxMenuItems()
+ {
+ rowsItem.setSelected(table.getRowSelectionAllowed());
+ columnsItem.setSelected(table.getColumnSelectionAllowed());
+ cellsItem.setSelected(table.getCellSelectionEnabled());
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/tableRowColumn/Pluto.gif b/corejava第10版/v2ch10/tableRowColumn/Pluto.gif
new file mode 100644
index 0000000..3909638
Binary files /dev/null and b/corejava第10版/v2ch10/tableRowColumn/Pluto.gif differ
diff --git a/corejava第10版/v2ch10/tableRowColumn/Saturn.gif b/corejava第10版/v2ch10/tableRowColumn/Saturn.gif
new file mode 100644
index 0000000..b4c6144
Binary files /dev/null and b/corejava第10版/v2ch10/tableRowColumn/Saturn.gif differ
diff --git a/corejava第10版/v2ch10/tableRowColumn/TableRowColumnTest.java b/corejava第10版/v2ch10/tableRowColumn/TableRowColumnTest.java
new file mode 100644
index 0000000..6c78952
--- /dev/null
+++ b/corejava第10版/v2ch10/tableRowColumn/TableRowColumnTest.java
@@ -0,0 +1,23 @@
+package tableRowColumn;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates how to work with rows and columns in a table.
+ * @version 1.22 2016-05-10
+ * @author Cay Horstmann
+ */
+public class TableRowColumnTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new PlanetTableFrame();
+ frame.setTitle("TableRowColumnTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/tableRowColumn/Uranus.gif b/corejava第10版/v2ch10/tableRowColumn/Uranus.gif
new file mode 100644
index 0000000..e9baa5d
Binary files /dev/null and b/corejava第10版/v2ch10/tableRowColumn/Uranus.gif differ
diff --git a/corejava第10版/v2ch10/tableRowColumn/Venus.gif b/corejava第10版/v2ch10/tableRowColumn/Venus.gif
new file mode 100644
index 0000000..8552313
Binary files /dev/null and b/corejava第10版/v2ch10/tableRowColumn/Venus.gif differ
diff --git a/corejava第10版/v2ch10/tableSelection/TableSelectionFrame.java b/corejava第10版/v2ch10/tableSelection/TableSelectionFrame.java
new file mode 100644
index 0000000..f8c5370
--- /dev/null
+++ b/corejava第10版/v2ch10/tableSelection/TableSelectionFrame.java
@@ -0,0 +1,147 @@
+package tableSelection;
+
+import java.util.*;
+
+import javax.swing.*;
+import javax.swing.table.*;
+
+/**
+ * This frame shows a multiplication table and has menus for setting the row/column/cell selection modes, and for adding
+ * and removing rows and columns.
+ */
+class TableSelectionFrame extends JFrame
+{
+ private DefaultTableModel model;
+ private JTable table;
+ private ArrayList removedColumns;
+
+ private static final int DEFAULT_WIDTH = 400;
+ private static final int DEFAULT_HEIGHT = 300;
+
+ public TableSelectionFrame()
+ {
+ setTitle("TableSelectionTest");
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ // set up multiplication table
+
+ model = new DefaultTableModel(10, 10);
+
+ for (int i = 0; i < model.getRowCount(); i++)
+ for (int j = 0; j < model.getColumnCount(); j++)
+ model.setValueAt((i + 1) * (j + 1), i, j);
+
+ table = new JTable(model);
+
+ add(new JScrollPane(table), "Center");
+
+ removedColumns = new ArrayList();
+
+ // create menu
+
+ JMenuBar menuBar = new JMenuBar();
+ setJMenuBar(menuBar);
+
+ JMenu selectionMenu = new JMenu("Selection");
+ menuBar.add(selectionMenu);
+
+ final JCheckBoxMenuItem rowsItem = new JCheckBoxMenuItem("Rows");
+ final JCheckBoxMenuItem columnsItem = new JCheckBoxMenuItem("Columns");
+ final JCheckBoxMenuItem cellsItem = new JCheckBoxMenuItem("Cells");
+
+ rowsItem.setSelected(table.getRowSelectionAllowed());
+ columnsItem.setSelected(table.getColumnSelectionAllowed());
+ cellsItem.setSelected(table.getCellSelectionEnabled());
+
+ rowsItem.addActionListener(event ->
+ {
+ table.clearSelection();
+ table.setRowSelectionAllowed(rowsItem.isSelected());
+ cellsItem.setSelected(table.getCellSelectionEnabled());
+ });
+ selectionMenu.add(rowsItem);
+
+ columnsItem.addActionListener(event ->
+ {
+ table.clearSelection();
+ table.setColumnSelectionAllowed(columnsItem.isSelected());
+ cellsItem.setSelected(table.getCellSelectionEnabled());
+ });
+ selectionMenu.add(columnsItem);
+
+ cellsItem.addActionListener(event ->
+ {
+ table.clearSelection();
+ table.setCellSelectionEnabled(cellsItem.isSelected());
+ rowsItem.setSelected(table.getRowSelectionAllowed());
+ columnsItem.setSelected(table.getColumnSelectionAllowed());
+ });
+ selectionMenu.add(cellsItem);
+
+ JMenu tableMenu = new JMenu("Edit");
+ menuBar.add(tableMenu);
+
+ JMenuItem hideColumnsItem = new JMenuItem("Hide Columns");
+ hideColumnsItem.addActionListener(event ->
+ {
+ int[] selected = table.getSelectedColumns();
+ TableColumnModel columnModel = table.getColumnModel();
+
+ // remove columns from view, starting at the last
+ // index so that column numbers aren't affected
+
+ for (int i = selected.length - 1; i >= 0; i--)
+ {
+ TableColumn column = columnModel.getColumn(selected[i]);
+ table.removeColumn(column);
+
+ // store removed columns for "show columns" command
+
+ removedColumns.add(column);
+ }
+ });
+ tableMenu.add(hideColumnsItem);
+
+ JMenuItem showColumnsItem = new JMenuItem("Show Columns");
+ showColumnsItem.addActionListener(event ->
+ {
+ // restore all removed columns
+ for (TableColumn tc : removedColumns)
+ table.addColumn(tc);
+ removedColumns.clear();
+ });
+ tableMenu.add(showColumnsItem);
+
+ JMenuItem addRowItem = new JMenuItem("Add Row");
+ addRowItem.addActionListener(event ->
+ {
+ // add a new row to the multiplication table in
+ // the model
+
+ Integer[] newCells = new Integer[model.getColumnCount()];
+ for (int i = 0; i < newCells.length; i++)
+ newCells[i] = (i + 1) * (model.getRowCount() + 1);
+ model.addRow(newCells);
+ });
+ tableMenu.add(addRowItem);
+
+ JMenuItem removeRowsItem = new JMenuItem("Remove Rows");
+ removeRowsItem.addActionListener(event ->
+ {
+ int[] selected = table.getSelectedRows();
+
+ for (int i = selected.length - 1; i >= 0; i--)
+ model.removeRow(selected[i]);
+ });
+ tableMenu.add(removeRowsItem);
+
+ JMenuItem clearCellsItem = new JMenuItem("Clear Cells");
+ clearCellsItem.addActionListener(event ->
+ {
+ for (int i = 0; i < table.getRowCount(); i++)
+ for (int j = 0; j < table.getColumnCount(); j++)
+ if (table.isCellSelected(i, j)) table.setValueAt(0, i, j);
+ });
+ tableMenu.add(clearCellsItem);
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/tableSelection/TableSelectionTest.java b/corejava第10版/v2ch10/tableSelection/TableSelectionTest.java
new file mode 100644
index 0000000..a37b1bb
--- /dev/null
+++ b/corejava第10版/v2ch10/tableSelection/TableSelectionTest.java
@@ -0,0 +1,25 @@
+package tableSelection;
+
+/**
+ @version 1.04 2016-05-10
+ @author Cay Horstmann
+ */
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates selection, addition, and removal of rows and columns.
+ */
+public class TableSelectionTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new TableSelectionFrame();
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/textChange/ChangeTrackingTest.java b/corejava第10版/v2ch10/textChange/ChangeTrackingTest.java
new file mode 100644
index 0000000..cd58eac
--- /dev/null
+++ b/corejava第10版/v2ch10/textChange/ChangeTrackingTest.java
@@ -0,0 +1,22 @@
+package textChange;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * @version 1.41 2016-05-10
+ * @author Cay Horstmann
+ */
+public class ChangeTrackingTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new ColorFrame();
+ frame.setTitle("ChangeTrackingTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/textChange/ColorFrame.java b/corejava第10版/v2ch10/textChange/ColorFrame.java
new file mode 100644
index 0000000..e8a8ac7
--- /dev/null
+++ b/corejava第10版/v2ch10/textChange/ColorFrame.java
@@ -0,0 +1,64 @@
+package textChange;
+
+import java.awt.*;
+import javax.swing.*;
+import javax.swing.event.*;
+
+/**
+ * A frame with three text fields to set the background color.
+ */
+public class ColorFrame extends JFrame
+{
+ private JPanel panel;
+ private JTextField redField;
+ private JTextField greenField;
+ private JTextField blueField;
+
+ public ColorFrame()
+ {
+ DocumentListener listener = new DocumentListener()
+ {
+ public void insertUpdate(DocumentEvent event) { setColor(); }
+ public void removeUpdate(DocumentEvent event) { setColor(); }
+ public void changedUpdate(DocumentEvent event) {}
+ };
+
+ panel = new JPanel();
+
+ panel.add(new JLabel("Red:"));
+ redField = new JTextField("255", 3);
+ panel.add(redField);
+ redField.getDocument().addDocumentListener(listener);
+
+ panel.add(new JLabel("Green:"));
+ greenField = new JTextField("255", 3);
+ panel.add(greenField);
+ greenField.getDocument().addDocumentListener(listener);
+
+ panel.add(new JLabel("Blue:"));
+ blueField = new JTextField("255", 3);
+ panel.add(blueField);
+ blueField.getDocument().addDocumentListener(listener);
+
+ add(panel);
+ pack();
+ }
+
+ /**
+ * Set the background color to the values stored in the text fields.
+ */
+ public void setColor()
+ {
+ try
+ {
+ int red = Integer.parseInt(redField.getText().trim());
+ int green = Integer.parseInt(greenField.getText().trim());
+ int blue = Integer.parseInt(blueField.getText().trim());
+ panel.setBackground(new Color(red, green, blue));
+ }
+ catch (NumberFormatException e)
+ {
+ // don't set the color if the input can't be parsed
+ }
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/textFormat/FormatTest.java b/corejava第10版/v2ch10/textFormat/FormatTest.java
new file mode 100644
index 0000000..792aa01
--- /dev/null
+++ b/corejava第10版/v2ch10/textFormat/FormatTest.java
@@ -0,0 +1,24 @@
+package textFormat;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * A program to test formatted text fields
+ * @version 1.04 2016-05-10
+ * @author Cay Horstmann
+ */
+public class FormatTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new FormatTestFrame();
+ frame.setTitle("FormatTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
diff --git a/corejava第10版/v2ch10/textFormat/FormatTestFrame.java b/corejava第10版/v2ch10/textFormat/FormatTestFrame.java
new file mode 100644
index 0000000..00d0ace
--- /dev/null
+++ b/corejava第10版/v2ch10/textFormat/FormatTestFrame.java
@@ -0,0 +1,151 @@
+package textFormat;
+
+import java.awt.*;
+import java.net.*;
+import java.text.*;
+import java.util.*;
+
+import javax.swing.*;
+import javax.swing.text.*;
+
+/**
+ * A frame with a collection of formatted text fields and a button that displays the field values.
+ */
+public class FormatTestFrame extends JFrame
+{
+ private DocumentFilter filter = new IntFilter();
+ private JButton okButton;
+ private JPanel mainPanel;
+
+ public FormatTestFrame()
+ {
+ JPanel buttonPanel = new JPanel();
+ okButton = new JButton("Ok");
+ buttonPanel.add(okButton);
+ add(buttonPanel, BorderLayout.SOUTH);
+
+ mainPanel = new JPanel();
+ mainPanel.setLayout(new GridLayout(0, 3));
+ add(mainPanel, BorderLayout.CENTER);
+
+ JFormattedTextField intField = new JFormattedTextField(NumberFormat.getIntegerInstance());
+ intField.setValue(new Integer(100));
+ addRow("Number:", intField);
+
+ JFormattedTextField intField2 = new JFormattedTextField(NumberFormat.getIntegerInstance());
+ intField2.setValue(new Integer(100));
+ intField2.setFocusLostBehavior(JFormattedTextField.COMMIT);
+ addRow("Number (Commit behavior):", intField2);
+
+ JFormattedTextField intField3 = new JFormattedTextField(new InternationalFormatter(
+ NumberFormat.getIntegerInstance())
+ {
+ protected DocumentFilter getDocumentFilter()
+ {
+ return filter;
+ }
+
+ });
+ intField3.setValue(new Integer(100));
+ addRow("Filtered Number", intField3);
+
+ JFormattedTextField intField4 = new JFormattedTextField(NumberFormat.getIntegerInstance());
+ intField4.setValue(new Integer(100));
+ intField4.setInputVerifier(new InputVerifier()
+ {
+ public boolean verify(JComponent component)
+ {
+ JFormattedTextField field = (JFormattedTextField) component;
+ return field.isEditValid();
+ }
+ });
+ addRow("Verified Number:", intField4);
+
+ JFormattedTextField currencyField = new JFormattedTextField(NumberFormat
+ .getCurrencyInstance());
+ currencyField.setValue(new Double(10));
+ addRow("Currency:", currencyField);
+
+ JFormattedTextField dateField = new JFormattedTextField(DateFormat.getDateInstance());
+ dateField.setValue(new Date());
+ addRow("Date (default):", dateField);
+
+ DateFormat format = DateFormat.getDateInstance(DateFormat.SHORT);
+ format.setLenient(false);
+ JFormattedTextField dateField2 = new JFormattedTextField(format);
+ dateField2.setValue(new Date());
+ addRow("Date (short, not lenient):", dateField2);
+
+ try
+ {
+ DefaultFormatter formatter = new DefaultFormatter();
+ formatter.setOverwriteMode(false);
+ JFormattedTextField urlField = new JFormattedTextField(formatter);
+ urlField.setValue(new URL("http://java.sun.com"));
+ addRow("URL:", urlField);
+ }
+ catch (MalformedURLException ex)
+ {
+ ex.printStackTrace();
+ }
+
+ try
+ {
+ MaskFormatter formatter = new MaskFormatter("###-##-####");
+ formatter.setPlaceholderCharacter('0');
+ JFormattedTextField ssnField = new JFormattedTextField(formatter);
+ ssnField.setValue("078-05-1120");
+ addRow("SSN Mask:", ssnField);
+ }
+ catch (ParseException ex)
+ {
+ ex.printStackTrace();
+ }
+
+ JFormattedTextField ipField = new JFormattedTextField(new IPAddressFormatter());
+ ipField.setValue(new byte[] { (byte) 130, 65, 86, 66 });
+ addRow("IP Address:", ipField);
+ pack();
+ }
+
+ /**
+ * Adds a row to the main panel.
+ * @param labelText the label of the field
+ * @param field the sample field
+ */
+ public void addRow(String labelText, final JFormattedTextField field)
+ {
+ mainPanel.add(new JLabel(labelText));
+ mainPanel.add(field);
+ final JLabel valueLabel = new JLabel();
+ mainPanel.add(valueLabel);
+ okButton.addActionListener(event ->
+ {
+ Object value = field.getValue();
+ Class> cl = value.getClass();
+ String text = null;
+ if (cl.isArray())
+ {
+ if (cl.getComponentType().isPrimitive())
+ {
+ try
+ {
+ text = Arrays.class.getMethod("toString", cl).invoke(null, value)
+ .toString();
+ }
+ catch (ReflectiveOperationException ex)
+ {
+ // ignore reflection exceptions
+ }
+ }
+ else text = Arrays.toString((Object[]) value);
+ }
+ else text = value.toString();
+ valueLabel.setText(text);
+ });
+ }
+}
+
+
+
+
diff --git a/corejava第10版/v2ch10/textFormat/IPAddressFormatter.java b/corejava第10版/v2ch10/textFormat/IPAddressFormatter.java
new file mode 100644
index 0000000..27c0f5f
--- /dev/null
+++ b/corejava第10版/v2ch10/textFormat/IPAddressFormatter.java
@@ -0,0 +1,50 @@
+package textFormat;
+
+import java.text.*;
+import java.util.*;
+import javax.swing.text.*;
+
+/**
+ * A formatter for 4-byte IP addresses of the form a.b.c.d
+ */
+public class IPAddressFormatter extends DefaultFormatter
+{
+ public String valueToString(Object value) throws ParseException
+ {
+ if (!(value instanceof byte[])) throw new ParseException("Not a byte[]", 0);
+ byte[] a = (byte[]) value;
+ if (a.length != 4) throw new ParseException("Length != 4", 0);
+ StringBuilder builder = new StringBuilder();
+ for (int i = 0; i < 4; i++)
+ {
+ int b = a[i];
+ if (b < 0) b += 256;
+ builder.append(String.valueOf(b));
+ if (i < 3) builder.append('.');
+ }
+ return builder.toString();
+ }
+
+ public Object stringToValue(String text) throws ParseException
+ {
+ StringTokenizer tokenizer = new StringTokenizer(text, ".");
+ byte[] a = new byte[4];
+ for (int i = 0; i < 4; i++)
+ {
+ int b = 0;
+ if (!tokenizer.hasMoreTokens()) throw new ParseException("Too few bytes", 0);
+ try
+ {
+ b = Integer.parseInt(tokenizer.nextToken());
+ }
+ catch (NumberFormatException e)
+ {
+ throw new ParseException("Not an integer", 0);
+ }
+ if (b < 0 || b >= 256) throw new ParseException("Byte out of range", 0);
+ a[i] = (byte) b;
+ }
+ if (tokenizer.hasMoreTokens()) throw new ParseException("Too many bytes", 0);
+ return a;
+ }
+}
diff --git a/corejava第10版/v2ch10/textFormat/IntFilter.java b/corejava第10版/v2ch10/textFormat/IntFilter.java
new file mode 100644
index 0000000..afb347f
--- /dev/null
+++ b/corejava第10版/v2ch10/textFormat/IntFilter.java
@@ -0,0 +1,53 @@
+package textFormat;
+
+import javax.swing.text.*;
+
+/**
+ * A filter that restricts input to digits and a '-' sign.
+ */
+public class IntFilter extends DocumentFilter
+{
+ public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr)
+ throws BadLocationException
+ {
+ StringBuilder builder = new StringBuilder(string);
+ for (int i = builder.length() - 1; i >= 0; i--)
+ {
+ int cp = builder.codePointAt(i);
+ if (!Character.isDigit(cp) && cp != '-')
+ {
+ builder.deleteCharAt(i);
+ if (Character.isSupplementaryCodePoint(cp))
+ {
+ i--;
+ builder.deleteCharAt(i);
+ }
+ }
+ }
+ super.insertString(fb, offset, builder.toString(), attr);
+ }
+
+ public void replace(FilterBypass fb, int offset, int length, String string, AttributeSet attr)
+ throws BadLocationException
+ {
+ if (string != null)
+ {
+ StringBuilder builder = new StringBuilder(string);
+ for (int i = builder.length() - 1; i >= 0; i--)
+ {
+ int cp = builder.codePointAt(i);
+ if (!Character.isDigit(cp) && cp != '-')
+ {
+ builder.deleteCharAt(i);
+ if (Character.isSupplementaryCodePoint(cp))
+ {
+ i--;
+ builder.deleteCharAt(i);
+ }
+ }
+ }
+ string = builder.toString();
+ }
+ super.replace(fb, offset, length, string, attr);
+ }
+}
diff --git a/corejava第10版/v2ch10/tree/SimpleTree.java b/corejava第10版/v2ch10/tree/SimpleTree.java
new file mode 100644
index 0000000..c7ad2dd
--- /dev/null
+++ b/corejava第10版/v2ch10/tree/SimpleTree.java
@@ -0,0 +1,23 @@
+package tree;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program shows a simple tree.
+ * @version 1.03 2016-05-10
+ * @author Cay Horstmann
+ */
+public class SimpleTree
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new SimpleTreeFrame();
+ frame.setTitle("SimpleTree");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
diff --git a/corejava第10版/v2ch10/tree/SimpleTreeFrame.java b/corejava第10版/v2ch10/tree/SimpleTreeFrame.java
new file mode 100644
index 0000000..9679d65
--- /dev/null
+++ b/corejava第10版/v2ch10/tree/SimpleTreeFrame.java
@@ -0,0 +1,45 @@
+package tree;
+
+import javax.swing.*;
+import javax.swing.tree.*;
+
+/**
+ * This frame contains a simple tree that displays a manually constructed tree model.
+ */
+public class SimpleTreeFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 200;
+
+ public SimpleTreeFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ // set up tree model data
+
+ DefaultMutableTreeNode root = new DefaultMutableTreeNode("World");
+ DefaultMutableTreeNode country = new DefaultMutableTreeNode("USA");
+ root.add(country);
+ DefaultMutableTreeNode state = new DefaultMutableTreeNode("California");
+ country.add(state);
+ DefaultMutableTreeNode city = new DefaultMutableTreeNode("San Jose");
+ state.add(city);
+ city = new DefaultMutableTreeNode("Cupertino");
+ state.add(city);
+ state = new DefaultMutableTreeNode("Michigan");
+ country.add(state);
+ city = new DefaultMutableTreeNode("Ann Arbor");
+ state.add(city);
+ country = new DefaultMutableTreeNode("Germany");
+ root.add(country);
+ state = new DefaultMutableTreeNode("Schleswig-Holstein");
+ country.add(state);
+ city = new DefaultMutableTreeNode("Kiel");
+ state.add(city);
+
+ // construct tree and put it in a scroll pane
+
+ JTree tree = new JTree(root);
+ add(new JScrollPane(tree));
+ }
+}
diff --git a/corejava第10版/v2ch10/treeEdit/TreeEditFrame.java b/corejava第10版/v2ch10/treeEdit/TreeEditFrame.java
new file mode 100644
index 0000000..7ca314f
--- /dev/null
+++ b/corejava第10版/v2ch10/treeEdit/TreeEditFrame.java
@@ -0,0 +1,124 @@
+package treeEdit;
+
+import java.awt.*;
+
+import javax.swing.*;
+import javax.swing.tree.*;
+
+/**
+ * A frame with a tree and buttons to edit the tree.
+ */
+public class TreeEditFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 400;
+ private static final int DEFAULT_HEIGHT = 200;
+
+ private DefaultTreeModel model;
+ private JTree tree;
+
+ public TreeEditFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ // construct tree
+
+ TreeNode root = makeSampleTree();
+ model = new DefaultTreeModel(root);
+ tree = new JTree(model);
+ tree.setEditable(true);
+
+ // add scroll pane with tree
+
+ JScrollPane scrollPane = new JScrollPane(tree);
+ add(scrollPane, BorderLayout.CENTER);
+
+ makeButtons();
+ }
+
+ public TreeNode makeSampleTree()
+ {
+ DefaultMutableTreeNode root = new DefaultMutableTreeNode("World");
+ DefaultMutableTreeNode country = new DefaultMutableTreeNode("USA");
+ root.add(country);
+ DefaultMutableTreeNode state = new DefaultMutableTreeNode("California");
+ country.add(state);
+ DefaultMutableTreeNode city = new DefaultMutableTreeNode("San Jose");
+ state.add(city);
+ city = new DefaultMutableTreeNode("San Diego");
+ state.add(city);
+ state = new DefaultMutableTreeNode("Michigan");
+ country.add(state);
+ city = new DefaultMutableTreeNode("Ann Arbor");
+ state.add(city);
+ country = new DefaultMutableTreeNode("Germany");
+ root.add(country);
+ state = new DefaultMutableTreeNode("Schleswig-Holstein");
+ country.add(state);
+ city = new DefaultMutableTreeNode("Kiel");
+ state.add(city);
+ return root;
+ }
+
+ /**
+ * Makes the buttons to add a sibling, add a child, and delete a node.
+ */
+ public void makeButtons()
+ {
+ JPanel panel = new JPanel();
+ JButton addSiblingButton = new JButton("Add Sibling");
+ addSiblingButton.addActionListener(event ->
+ {
+ DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree
+ .getLastSelectedPathComponent();
+
+ if (selectedNode == null) return;
+
+ DefaultMutableTreeNode parent = (DefaultMutableTreeNode) selectedNode.getParent();
+
+ if (parent == null) return;
+
+ DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("New");
+
+ int selectedIndex = parent.getIndex(selectedNode);
+ model.insertNodeInto(newNode, parent, selectedIndex + 1);
+
+ // now display new node
+
+ TreeNode[] nodes = model.getPathToRoot(newNode);
+ TreePath path = new TreePath(nodes);
+ tree.scrollPathToVisible(path);
+ });
+ panel.add(addSiblingButton);
+
+ JButton addChildButton = new JButton("Add Child");
+ addChildButton.addActionListener(event ->
+ {
+ DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree
+ .getLastSelectedPathComponent();
+
+ if (selectedNode == null) return;
+
+ DefaultMutableTreeNode newNode = new DefaultMutableTreeNode("New");
+ model.insertNodeInto(newNode, selectedNode, selectedNode.getChildCount());
+
+ // now display new node
+
+ TreeNode[] nodes = model.getPathToRoot(newNode);
+ TreePath path = new TreePath(nodes);
+ tree.scrollPathToVisible(path);
+ });
+ panel.add(addChildButton);
+
+ JButton deleteButton = new JButton("Delete");
+ deleteButton.addActionListener(event ->
+ {
+ DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree
+ .getLastSelectedPathComponent();
+
+ if (selectedNode != null && selectedNode.getParent() != null) model
+ .removeNodeFromParent(selectedNode);
+ });
+ panel.add(deleteButton);
+ add(panel, BorderLayout.SOUTH);
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/treeEdit/TreeEditTest.java b/corejava第10版/v2ch10/treeEdit/TreeEditTest.java
new file mode 100644
index 0000000..f00ec01
--- /dev/null
+++ b/corejava第10版/v2ch10/treeEdit/TreeEditTest.java
@@ -0,0 +1,23 @@
+package treeEdit;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates tree editing.
+ * @version 1.04 2016-05-10
+ * @author Cay Horstmann
+ */
+public class TreeEditTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new TreeEditFrame();
+ frame.setTitle("TreeEditTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch10/treeModel/ObjectInspectorFrame.java b/corejava第10版/v2ch10/treeModel/ObjectInspectorFrame.java
new file mode 100644
index 0000000..a781808
--- /dev/null
+++ b/corejava第10版/v2ch10/treeModel/ObjectInspectorFrame.java
@@ -0,0 +1,30 @@
+package treeModel;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This frame holds the object tree.
+ */
+public class ObjectInspectorFrame extends JFrame
+{
+ private JTree tree;
+ private static final int DEFAULT_WIDTH = 400;
+ private static final int DEFAULT_HEIGHT = 300;
+
+ public ObjectInspectorFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ // we inspect this frame object
+
+ Variable v = new Variable(getClass(), "this", this);
+ ObjectTreeModel model = new ObjectTreeModel();
+ model.setRoot(v);
+
+ // construct and show tree
+
+ tree = new JTree(model);
+ add(new JScrollPane(tree), BorderLayout.CENTER);
+ }
+}
diff --git a/corejava第10版/v2ch10/treeModel/ObjectInspectorTest.java b/corejava第10版/v2ch10/treeModel/ObjectInspectorTest.java
new file mode 100644
index 0000000..75931d9
--- /dev/null
+++ b/corejava第10版/v2ch10/treeModel/ObjectInspectorTest.java
@@ -0,0 +1,26 @@
+package treeModel;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates how to use a custom tree model. It displays the fields of an object.
+ * @version 1.05 2016-05-10
+ * @author Cay Horstmann
+ */
+public class ObjectInspectorTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new ObjectInspectorFrame();
+ frame.setTitle("ObjectInspectorTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+
+
diff --git a/corejava第10版/v2ch10/treeModel/ObjectTreeModel.java b/corejava第10版/v2ch10/treeModel/ObjectTreeModel.java
new file mode 100644
index 0000000..e8c1b52
--- /dev/null
+++ b/corejava第10版/v2ch10/treeModel/ObjectTreeModel.java
@@ -0,0 +1,94 @@
+package treeModel;
+
+import java.lang.reflect.*;
+import java.util.*;
+import javax.swing.event.*;
+import javax.swing.tree.*;
+
+/**
+ * This tree model describes the tree structure of a Java object. Children are the objects that are
+ * stored in instance variables.
+ */
+public class ObjectTreeModel implements TreeModel
+{
+ private Variable root;
+ private EventListenerList listenerList = new EventListenerList();
+
+ /**
+ * Constructs an empty tree.
+ */
+ public ObjectTreeModel()
+ {
+ root = null;
+ }
+
+ /**
+ * Sets the root to a given variable.
+ * @param v the variable that is being described by this tree
+ */
+ public void setRoot(Variable v)
+ {
+ Variable oldRoot = v;
+ root = v;
+ fireTreeStructureChanged(oldRoot);
+ }
+
+ public Object getRoot()
+ {
+ return root;
+ }
+
+ public int getChildCount(Object parent)
+ {
+ return ((Variable) parent).getFields().size();
+ }
+
+ public Object getChild(Object parent, int index)
+ {
+ ArrayList fields = ((Variable) parent).getFields();
+ Field f = (Field) fields.get(index);
+ Object parentValue = ((Variable) parent).getValue();
+ try
+ {
+ return new Variable(f.getType(), f.getName(), f.get(parentValue));
+ }
+ catch (IllegalAccessException e)
+ {
+ return null;
+ }
+ }
+
+ public int getIndexOfChild(Object parent, Object child)
+ {
+ int n = getChildCount(parent);
+ for (int i = 0; i < n; i++)
+ if (getChild(parent, i).equals(child)) return i;
+ return -1;
+ }
+
+ public boolean isLeaf(Object node)
+ {
+ return getChildCount(node) == 0;
+ }
+
+ public void valueForPathChanged(TreePath path, Object newValue)
+ {
+ }
+
+ public void addTreeModelListener(TreeModelListener l)
+ {
+ listenerList.add(TreeModelListener.class, l);
+ }
+
+ public void removeTreeModelListener(TreeModelListener l)
+ {
+ listenerList.remove(TreeModelListener.class, l);
+ }
+
+ protected void fireTreeStructureChanged(Object oldRoot)
+ {
+ TreeModelEvent event = new TreeModelEvent(this, new Object[] { oldRoot });
+ for (TreeModelListener l : listenerList.getListeners(TreeModelListener.class))
+ l.treeStructureChanged(event);
+ }
+}
diff --git a/corejava第10版/v2ch10/treeModel/Variable.java b/corejava第10版/v2ch10/treeModel/Variable.java
new file mode 100644
index 0000000..5e4cebe
--- /dev/null
+++ b/corejava第10版/v2ch10/treeModel/Variable.java
@@ -0,0 +1,72 @@
+package treeModel;
+
+import java.lang.reflect.*;
+import java.util.*;
+
+/**
+ * A variable with a type, name, and value.
+ */
+public class Variable
+{
+ private Class> type;
+ private String name;
+ private Object value;
+ private ArrayList fields;
+
+ /**
+ * Construct a variable.
+ * @param aType the type
+ * @param aName the name
+ * @param aValue the value
+ */
+ public Variable(Class> aType, String aName, Object aValue)
+ {
+ type = aType;
+ name = aName;
+ value = aValue;
+ fields = new ArrayList<>();
+
+ // find all fields if we have a class type except we don't expand strings and null values
+
+ if (!type.isPrimitive() && !type.isArray() && !type.equals(String.class) && value != null)
+ {
+ // get fields from the class and all superclasses
+ for (Class> c = value.getClass(); c != null; c = c.getSuperclass())
+ {
+ Field[] fs = c.getDeclaredFields();
+ AccessibleObject.setAccessible(fs, true);
+
+ // get all nonstatic fields
+ for (Field f : fs)
+ if ((f.getModifiers() & Modifier.STATIC) == 0) fields.add(f);
+ }
+ }
+ }
+
+ /**
+ * Gets the value of this variable.
+ * @return the value
+ */
+ public Object getValue()
+ {
+ return value;
+ }
+
+ /**
+ * Gets all nonstatic fields of this variable.
+ * @return an array list of variables describing the fields
+ */
+ public ArrayList getFields()
+ {
+ return fields;
+ }
+
+ public String toString()
+ {
+ String r = type + " " + name;
+ if (type.isPrimitive()) r += "=" + value;
+ else if (type.equals(String.class)) r += "=" + value;
+ else if (value == null) r += "=null";
+ return r;
+ }
+}
diff --git a/corejava第10版/v2ch10/treeRender/ClassNameTreeCellRenderer.java b/corejava第10版/v2ch10/treeRender/ClassNameTreeCellRenderer.java
new file mode 100644
index 0000000..b10dd74
--- /dev/null
+++ b/corejava第10版/v2ch10/treeRender/ClassNameTreeCellRenderer.java
@@ -0,0 +1,37 @@
+package treeRender;
+
+import java.awt.*;
+import java.lang.reflect.*;
+import javax.swing.*;
+import javax.swing.tree.*;
+
+/**
+ * This class renders a class name either in plain or italic. Abstract classes are italic.
+ */
+public class ClassNameTreeCellRenderer extends DefaultTreeCellRenderer
+{
+ private Font plainFont = null;
+ private Font italicFont = null;
+
+ public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected,
+ boolean expanded, boolean leaf, int row, boolean hasFocus)
+ {
+ super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
+ // get the user object
+ DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;
+ Class> c = (Class>) node.getUserObject();
+
+ // the first time, derive italic font from plain font
+ if (plainFont == null)
+ {
+ plainFont = getFont();
+ // the tree cell renderer is sometimes called with a label that has a null font
+ if (plainFont != null) italicFont = plainFont.deriveFont(Font.ITALIC);
+ }
+
+ // set font to italic if the class is abstract, plain otherwise
+ if ((c.getModifiers() & Modifier.ABSTRACT) == 0) setFont(plainFont);
+ else setFont(italicFont);
+ return this;
+ }
+}
diff --git a/corejava第10版/v2ch10/treeRender/ClassTree.java b/corejava第10版/v2ch10/treeRender/ClassTree.java
new file mode 100644
index 0000000..a6301b9
--- /dev/null
+++ b/corejava第10版/v2ch10/treeRender/ClassTree.java
@@ -0,0 +1,24 @@
+package treeRender;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates cell rendering and listening to tree selection events.
+ * @version 1.04 2016-05-10
+ * @author Cay Horstmann
+ */
+public class ClassTree
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new ClassTreeFrame();
+ frame.setTitle("ClassTree");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
diff --git a/corejava第10版/v2ch10/treeRender/ClassTreeFrame.java b/corejava第10版/v2ch10/treeRender/ClassTreeFrame.java
new file mode 100644
index 0000000..5edcf2c
--- /dev/null
+++ b/corejava第10版/v2ch10/treeRender/ClassTreeFrame.java
@@ -0,0 +1,182 @@
+package treeRender;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.lang.reflect.*;
+import java.util.*;
+
+import javax.swing.*;
+import javax.swing.tree.*;
+
+/**
+ * This frame displays the class tree, a text field, and an "Add" button to add more classes
+ * into the tree.
+ */
+public class ClassTreeFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 400;
+ private static final int DEFAULT_HEIGHT = 300;
+
+ private DefaultMutableTreeNode root;
+ private DefaultTreeModel model;
+ private JTree tree;
+ private JTextField textField;
+ private JTextArea textArea;
+
+ public ClassTreeFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ // the root of the class tree is Object
+ root = new DefaultMutableTreeNode(java.lang.Object.class);
+ model = new DefaultTreeModel(root);
+ tree = new JTree(model);
+
+ // add this class to populate the tree with some data
+ addClass(getClass());
+
+ // set up node icons
+ ClassNameTreeCellRenderer renderer = new ClassNameTreeCellRenderer();
+ renderer.setClosedIcon(new ImageIcon(getClass().getResource("red-ball.gif")));
+ renderer.setOpenIcon(new ImageIcon(getClass().getResource("yellow-ball.gif")));
+ renderer.setLeafIcon(new ImageIcon(getClass().getResource("blue-ball.gif")));
+ tree.setCellRenderer(renderer);
+
+ // set up selection mode
+ tree.addTreeSelectionListener(event ->
+ {
+ // the user selected a different node--update description
+ TreePath path = tree.getSelectionPath();
+ if (path == null) return;
+ DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) path
+ .getLastPathComponent();
+ Class> c = (Class>) selectedNode.getUserObject();
+ String description = getFieldDescription(c);
+ textArea.setText(description);
+ });
+ int mode = TreeSelectionModel.SINGLE_TREE_SELECTION;
+ tree.getSelectionModel().setSelectionMode(mode);
+
+ // this text area holds the class description
+ textArea = new JTextArea();
+
+ // add tree and text area
+ JPanel panel = new JPanel();
+ panel.setLayout(new GridLayout(1, 2));
+ panel.add(new JScrollPane(tree));
+ panel.add(new JScrollPane(textArea));
+
+ add(panel, BorderLayout.CENTER);
+
+ addTextField();
+ }
+
+ /**
+ * Add the text field and "Add" button to add a new class.
+ */
+ public void addTextField()
+ {
+ JPanel panel = new JPanel();
+
+ ActionListener addListener = event ->
+ {
+ // add the class whose name is in the text field
+ try
+ {
+ String text = textField.getText();
+ addClass(Class.forName(text)); // clear text field to indicate success
+ textField.setText("");
+ }
+ catch (ClassNotFoundException e)
+ {
+ JOptionPane.showMessageDialog(null, "Class not found");
+ }
+ };
+
+ // new class names are typed into this text field
+ textField = new JTextField(20);
+ textField.addActionListener(addListener);
+ panel.add(textField);
+
+ JButton addButton = new JButton("Add");
+ addButton.addActionListener(addListener);
+ panel.add(addButton);
+
+ add(panel, BorderLayout.SOUTH);
+ }
+
+ /**
+ * Finds an object in the tree.
+ * @param obj the object to find
+ * @return the node containing the object or null if the object is not present in the tree
+ */
+ @SuppressWarnings("unchecked")
+ public DefaultMutableTreeNode findUserObject(Object obj)
+ {
+ // find the node containing a user object
+ Enumeration e = (Enumeration) root.breadthFirstEnumeration();
+ while (e.hasMoreElements())
+ {
+ DefaultMutableTreeNode node = (DefaultMutableTreeNode) e.nextElement();
+ if (node.getUserObject().equals(obj)) return node;
+ }
+ return null;
+ }
+
+ /**
+ * Adds a new class and any parent classes that aren't yet part of the tree
+ * @param c the class to add
+ * @return the newly added node.
+ */
+ public DefaultMutableTreeNode addClass(Class> c)
+ {
+ // add a new class to the tree
+
+ // skip non-class types
+ if (c.isInterface() || c.isPrimitive()) return null;
+
+ // if the class is already in the tree, return its node
+ DefaultMutableTreeNode node = findUserObject(c);
+ if (node != null) return node;
+
+ // class isn't present--first add class parent recursively
+
+ Class> s = c.getSuperclass();
+
+ DefaultMutableTreeNode parent;
+ if (s == null) parent = root;
+ else parent = addClass(s);
+
+ // add the class as a child to the parent
+ DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(c);
+ model.insertNodeInto(newNode, parent, parent.getChildCount());
+
+ // make node visible
+ TreePath path = new TreePath(model.getPathToRoot(newNode));
+ tree.makeVisible(path);
+
+ return newNode;
+ }
+
+ /**
+ * Returns a description of the fields of a class.
+ * @param the class to be described
+ * @return a string containing all field types and names
+ */
+ public static String getFieldDescription(Class> c)
+ {
+ // use reflection to find types and names of fields
+ StringBuilder r = new StringBuilder();
+ Field[] fields = c.getDeclaredFields();
+ for (int i = 0; i < fields.length; i++)
+ {
+ Field f = fields[i];
+ if ((f.getModifiers() & Modifier.STATIC) != 0) r.append("static ");
+ r.append(f.getType().getName());
+ r.append(" ");
+ r.append(f.getName());
+ r.append("\n");
+ }
+ return r.toString();
+ }
+}
diff --git a/corejava第10版/v2ch10/treeRender/blue-ball.gif b/corejava第10版/v2ch10/treeRender/blue-ball.gif
new file mode 100644
index 0000000..edc29b7
Binary files /dev/null and b/corejava第10版/v2ch10/treeRender/blue-ball.gif differ
diff --git a/corejava第10版/v2ch10/treeRender/red-ball.gif b/corejava第10版/v2ch10/treeRender/red-ball.gif
new file mode 100644
index 0000000..dca9296
Binary files /dev/null and b/corejava第10版/v2ch10/treeRender/red-ball.gif differ
diff --git a/corejava第10版/v2ch10/treeRender/yellow-ball.gif b/corejava第10版/v2ch10/treeRender/yellow-ball.gif
new file mode 100644
index 0000000..2b8c0bb
Binary files /dev/null and b/corejava第10版/v2ch10/treeRender/yellow-ball.gif differ
diff --git a/corejava第10版/v2ch11/book/Banner.java b/corejava第10版/v2ch11/book/Banner.java
new file mode 100644
index 0000000..715816b
--- /dev/null
+++ b/corejava第10版/v2ch11/book/Banner.java
@@ -0,0 +1,120 @@
+package book;
+
+import java.awt.*;
+import java.awt.font.*;
+import java.awt.geom.*;
+import java.awt.print.*;
+
+/**
+ * A banner that prints a text string on multiple pages.
+ */
+public class Banner implements Printable
+{
+ private String message;
+ private double scale;
+
+ /**
+ * Constructs a banner.
+ * @param m the message string
+ */
+ public Banner(String m)
+ {
+ message = m;
+ }
+
+ /**
+ * Gets the page count of this section.
+ * @param g2 the graphics context
+ * @param pf the page format
+ * @return the number of pages needed
+ */
+ public int getPageCount(Graphics2D g2, PageFormat pf)
+ {
+ if (message.equals("")) return 0;
+ FontRenderContext context = g2.getFontRenderContext();
+ Font f = new Font("Serif", Font.PLAIN, 72);
+ Rectangle2D bounds = f.getStringBounds(message, context);
+ scale = pf.getImageableHeight() / bounds.getHeight();
+ double width = scale * bounds.getWidth();
+ int pages = (int) Math.ceil(width / pf.getImageableWidth());
+ return pages;
+ }
+
+ public int print(Graphics g, PageFormat pf, int page) throws PrinterException
+ {
+ Graphics2D g2 = (Graphics2D) g;
+ if (page > getPageCount(g2, pf)) return Printable.NO_SUCH_PAGE;
+ g2.translate(pf.getImageableX(), pf.getImageableY());
+
+ drawPage(g2, pf, page);
+ return Printable.PAGE_EXISTS;
+ }
+
+ public void drawPage(Graphics2D g2, PageFormat pf, int page)
+ {
+ if (message.equals("")) return;
+ page--; // account for cover page
+
+ drawCropMarks(g2, pf);
+ g2.clip(new Rectangle2D.Double(0, 0, pf.getImageableWidth(), pf.getImageableHeight()));
+ g2.translate(-page * pf.getImageableWidth(), 0);
+ g2.scale(scale, scale);
+ FontRenderContext context = g2.getFontRenderContext();
+ Font f = new Font("Serif", Font.PLAIN, 72);
+ TextLayout layout = new TextLayout(message, f, context);
+ AffineTransform transform = AffineTransform.getTranslateInstance(0, layout.getAscent());
+ Shape outline = layout.getOutline(transform);
+ g2.draw(outline);
+ }
+
+ /**
+ * Draws 1/2" crop marks in the corners of the page.
+ * @param g2 the graphics context
+ * @param pf the page format
+ */
+ public void drawCropMarks(Graphics2D g2, PageFormat pf)
+ {
+ final double C = 36; // crop mark length = 1/2 inch
+ double w = pf.getImageableWidth();
+ double h = pf.getImageableHeight();
+ g2.draw(new Line2D.Double(0, 0, 0, C));
+ g2.draw(new Line2D.Double(0, 0, C, 0));
+ g2.draw(new Line2D.Double(w, 0, w, C));
+ g2.draw(new Line2D.Double(w, 0, w - C, 0));
+ g2.draw(new Line2D.Double(0, h, 0, h - C));
+ g2.draw(new Line2D.Double(0, h, C, h));
+ g2.draw(new Line2D.Double(w, h, w, h - C));
+ g2.draw(new Line2D.Double(w, h, w - C, h));
+ }
+}
+
+/**
+ * This class prints a cover page with a title.
+ */
+class CoverPage implements Printable
+{
+ private String title;
+
+ /**
+ * Constructs a cover page.
+ * @param t the title
+ */
+ public CoverPage(String t)
+ {
+ title = t;
+ }
+
+ public int print(Graphics g, PageFormat pf, int page) throws PrinterException
+ {
+ if (page >= 1) return Printable.NO_SUCH_PAGE;
+ Graphics2D g2 = (Graphics2D) g;
+ g2.setPaint(Color.black);
+ g2.translate(pf.getImageableX(), pf.getImageableY());
+ FontRenderContext context = g2.getFontRenderContext();
+ Font f = g2.getFont();
+ TextLayout layout = new TextLayout(title, f, context);
+ float ascent = layout.getAscent();
+ g2.drawString(title, 0, ascent);
+ return Printable.PAGE_EXISTS;
+ }
+}
diff --git a/corejava第10版/v2ch11/book/BookTest.java b/corejava第10版/v2ch11/book/BookTest.java
new file mode 100644
index 0000000..c051228
--- /dev/null
+++ b/corejava第10版/v2ch11/book/BookTest.java
@@ -0,0 +1,25 @@
+package book;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates the printing of a multi-page book. It prints a "banner", by blowing up
+ * a text string to fill the entire page vertically. The program also contains a generic print
+ * preview dialog.
+ * @version 1.13 2016-05-10
+ * @author Cay Horstmann
+ */
+public class BookTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new BookTestFrame();
+ frame.setTitle("BookTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch11/book/BookTestFrame.java b/corejava第10版/v2ch11/book/BookTestFrame.java
new file mode 100644
index 0000000..de9dfc1
--- /dev/null
+++ b/corejava第10版/v2ch11/book/BookTestFrame.java
@@ -0,0 +1,85 @@
+package book;
+
+import java.awt.*;
+import java.awt.print.*;
+
+import javax.print.attribute.*;
+import javax.swing.*;
+
+/**
+ * This frame has a text field for the banner text and buttons for printing, page setup, and print
+ * preview.
+ */
+public class BookTestFrame extends JFrame
+{
+ private JTextField text;
+ private PageFormat pageFormat;
+ private PrintRequestAttributeSet attributes;
+
+ public BookTestFrame()
+ {
+ text = new JTextField();
+ add(text, BorderLayout.NORTH);
+
+ attributes = new HashPrintRequestAttributeSet();
+
+ JPanel buttonPanel = new JPanel();
+
+ JButton printButton = new JButton("Print");
+ buttonPanel.add(printButton);
+ printButton.addActionListener(event ->
+ {
+ try
+ {
+ PrinterJob job = PrinterJob.getPrinterJob();
+ job.setPageable(makeBook());
+ if (job.printDialog(attributes))
+ {
+ job.print(attributes);
+ }
+ }
+ catch (PrinterException e)
+ {
+ JOptionPane.showMessageDialog(BookTestFrame.this, e);
+ }
+ });
+
+ JButton pageSetupButton = new JButton("Page setup");
+ buttonPanel.add(pageSetupButton);
+ pageSetupButton.addActionListener(event ->
+ {
+ PrinterJob job = PrinterJob.getPrinterJob();
+ pageFormat = job.pageDialog(attributes);
+ });
+
+ JButton printPreviewButton = new JButton("Print preview");
+ buttonPanel.add(printPreviewButton);
+ printPreviewButton.addActionListener(event ->
+ {
+ PrintPreviewDialog dialog = new PrintPreviewDialog(makeBook());
+ dialog.setVisible(true);
+ });
+
+ add(buttonPanel, BorderLayout.SOUTH);
+ pack();
+ }
+
+ /**
+ * Makes a book that contains a cover page and the pages for the banner.
+ */
+ public Book makeBook()
+ {
+ if (pageFormat == null)
+ {
+ PrinterJob job = PrinterJob.getPrinterJob();
+ pageFormat = job.defaultPage();
+ }
+ Book book = new Book();
+ String message = text.getText();
+ Banner banner = new Banner(message);
+ int pageCount = banner.getPageCount((Graphics2D) getGraphics(), pageFormat);
+ book.append(new CoverPage(message + " (" + pageCount + " pages)"), pageFormat);
+ book.append(banner, pageFormat, pageCount);
+ return book;
+ }
+}
diff --git a/corejava第10版/v2ch11/book/PrintPreviewCanvas.java b/corejava第10版/v2ch11/book/PrintPreviewCanvas.java
new file mode 100644
index 0000000..9c889a7
--- /dev/null
+++ b/corejava第10版/v2ch11/book/PrintPreviewCanvas.java
@@ -0,0 +1,86 @@
+package book;
+
+import java.awt.*;
+import java.awt.geom.*;
+import java.awt.print.*;
+import javax.swing.*;
+
+/**
+ * The canvas for displaying the print preview.
+ */
+class PrintPreviewCanvas extends JComponent
+{
+ private Book book;
+ private int currentPage;
+
+ /**
+ * Constructs a print preview canvas.
+ * @param b the book to be previewed
+ */
+ public PrintPreviewCanvas(Book b)
+ {
+ book = b;
+ currentPage = 0;
+ }
+
+ public void paintComponent(Graphics g)
+ {
+ Graphics2D g2 = (Graphics2D) g;
+ PageFormat pageFormat = book.getPageFormat(currentPage);
+
+ double xoff; // x offset of page start in window
+ double yoff; // y offset of page start in window
+ double scale; // scale factor to fit page in window
+ double px = pageFormat.getWidth();
+ double py = pageFormat.getHeight();
+ double sx = getWidth() - 1;
+ double sy = getHeight() - 1;
+ if (px / py < sx / sy) // center horizontally
+ {
+ scale = sy / py;
+ xoff = 0.5 * (sx - scale * px);
+ yoff = 0;
+ }
+ else
+ // center vertically
+ {
+ scale = sx / px;
+ xoff = 0;
+ yoff = 0.5 * (sy - scale * py);
+ }
+ g2.translate((float) xoff, (float) yoff);
+ g2.scale((float) scale, (float) scale);
+
+ // draw page outline (ignoring margins)
+ Rectangle2D page = new Rectangle2D.Double(0, 0, px, py);
+ g2.setPaint(Color.white);
+ g2.fill(page);
+ g2.setPaint(Color.black);
+ g2.draw(page);
+
+ Printable printable = book.getPrintable(currentPage);
+ try
+ {
+ printable.print(g2, pageFormat, currentPage);
+ }
+ catch (PrinterException e)
+ {
+ g2.draw(new Line2D.Double(0, 0, px, py));
+ g2.draw(new Line2D.Double(px, 0, 0, py));
+ }
+ }
+
+ /**
+ * Flip the book by the given number of pages.
+ * @param by the number of pages to flip by. Negative values flip backwards.
+ */
+ public void flipPage(int by)
+ {
+ int newPage = currentPage + by;
+ if (0 <= newPage && newPage < book.getNumberOfPages())
+ {
+ currentPage = newPage;
+ repaint();
+ }
+ }
+}
diff --git a/corejava第10版/v2ch11/book/PrintPreviewDialog.java b/corejava第10版/v2ch11/book/PrintPreviewDialog.java
new file mode 100644
index 0000000..419622f
--- /dev/null
+++ b/corejava第10版/v2ch11/book/PrintPreviewDialog.java
@@ -0,0 +1,67 @@
+package book;
+
+import java.awt.*;
+import java.awt.print.*;
+
+import javax.swing.*;
+
+/**
+ * This class implements a generic print preview dialog.
+ */
+public class PrintPreviewDialog extends JDialog
+{
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 300;
+
+ private PrintPreviewCanvas canvas;
+
+ /**
+ * Constructs a print preview dialog.
+ * @param p a Printable
+ * @param pf the page format
+ * @param pages the number of pages in p
+ */
+ public PrintPreviewDialog(Printable p, PageFormat pf, int pages)
+ {
+ Book book = new Book();
+ book.append(p, pf, pages);
+ layoutUI(book);
+ }
+
+ /**
+ * Constructs a print preview dialog.
+ * @param b a Book
+ */
+ public PrintPreviewDialog(Book b)
+ {
+ layoutUI(b);
+ }
+
+ /**
+ * Lays out the UI of the dialog.
+ * @param book the book to be previewed
+ */
+ public void layoutUI(Book book)
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ canvas = new PrintPreviewCanvas(book);
+ add(canvas, BorderLayout.CENTER);
+
+ JPanel buttonPanel = new JPanel();
+
+ JButton nextButton = new JButton("Next");
+ buttonPanel.add(nextButton);
+ nextButton.addActionListener(event -> canvas.flipPage(1));
+
+ JButton previousButton = new JButton("Previous");
+ buttonPanel.add(previousButton);
+ previousButton.addActionListener(event -> canvas.flipPage(-1));
+
+ JButton closeButton = new JButton("Close");
+ buttonPanel.add(closeButton);
+ closeButton.addActionListener(event -> setVisible(false));
+
+ add(buttonPanel, BorderLayout.SOUTH);
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v2ch11/cj2.gif b/corejava第10版/v2ch11/cj2.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/cj2.gif
rename to corejava第10版/v2ch11/cj2.gif
diff --git a/javacore第11版/corejava/v2ch11/cj8v2.png b/corejava第10版/v2ch11/cj8v2.png
similarity index 100%
rename from javacore第11版/corejava/v2ch11/cj8v2.png
rename to corejava第10版/v2ch11/cj8v2.png
diff --git a/corejava第10版/v2ch11/composite/CompositeComponent.java b/corejava第10版/v2ch11/composite/CompositeComponent.java
new file mode 100644
index 0000000..b41dabc
--- /dev/null
+++ b/corejava第10版/v2ch11/composite/CompositeComponent.java
@@ -0,0 +1,58 @@
+package composite;
+
+import java.awt.*;
+import java.awt.geom.*;
+import java.awt.image.*;
+import javax.swing.*;
+
+/**
+ * This component draws two shapes, composed with a composition rule.
+ */
+class CompositeComponent extends JComponent
+{
+ private int rule;
+ private Shape shape1;
+ private Shape shape2;
+ private float alpha;
+
+ public CompositeComponent()
+ {
+ shape1 = new Ellipse2D.Double(100, 100, 150, 100);
+ shape2 = new Rectangle2D.Double(150, 150, 150, 100);
+ }
+
+ public void paintComponent(Graphics g)
+ {
+ Graphics2D g2 = (Graphics2D) g;
+
+ BufferedImage image = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
+ Graphics2D gImage = image.createGraphics();
+ gImage.setPaint(Color.red);
+ gImage.fill(shape1);
+ AlphaComposite composite = AlphaComposite.getInstance(rule, alpha);
+ gImage.setComposite(composite);
+ gImage.setPaint(Color.blue);
+ gImage.fill(shape2);
+ g2.drawImage(image, null, 0, 0);
+ }
+
+ /**
+ * Sets the composition rule.
+ * @param r the rule (as an AlphaComposite constant)
+ */
+ public void setRule(int r)
+ {
+ rule = r;
+ repaint();
+ }
+
+ /**
+ * Sets the alpha of the source.
+ * @param a the alpha value between 0 and 100
+ */
+ public void setAlpha(int a)
+ {
+ alpha = (float) a / 100.0F;
+ repaint();
+ }
+}
diff --git a/corejava第10版/v2ch11/composite/CompositeTest.java b/corejava第10版/v2ch11/composite/CompositeTest.java
new file mode 100644
index 0000000..46bcbbd
--- /dev/null
+++ b/corejava第10版/v2ch11/composite/CompositeTest.java
@@ -0,0 +1,24 @@
+package composite;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates the Porter-Duff composition rules.
+ * @version 1.04 2016-05-10
+ * @author Cay Horstmann
+ */
+public class CompositeTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new CompositeTestFrame();
+ frame.setTitle("CompositeTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
diff --git a/corejava第10版/v2ch11/composite/CompositeTestFrame.java b/corejava第10版/v2ch11/composite/CompositeTestFrame.java
new file mode 100644
index 0000000..e1f07f2
--- /dev/null
+++ b/corejava第10版/v2ch11/composite/CompositeTestFrame.java
@@ -0,0 +1,58 @@
+package composite;
+
+import java.awt.*;
+
+import javax.swing.*;
+
+/**
+ * This frame contains a combo box to choose a composition rule, a slider to change the source alpha
+ * channel, and a component that shows the composition.
+ */
+class CompositeTestFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 400;
+ private static final int DEFAULT_HEIGHT = 400;
+
+ private CompositeComponent canvas;
+ private JComboBox ruleCombo;
+ private JSlider alphaSlider;
+ private JTextField explanation;
+
+ public CompositeTestFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ canvas = new CompositeComponent();
+ add(canvas, BorderLayout.CENTER);
+
+ ruleCombo = new JComboBox<>(new Rule[] { new Rule("CLEAR", " ", " "),
+ new Rule("SRC", " S", " S"), new Rule("DST", " ", "DD"),
+ new Rule("SRC_OVER", " S", "DS"), new Rule("DST_OVER", " S", "DD"),
+ new Rule("SRC_IN", " ", " S"), new Rule("SRC_OUT", " S", " "),
+ new Rule("DST_IN", " ", " D"), new Rule("DST_OUT", " ", "D "),
+ new Rule("SRC_ATOP", " ", "DS"), new Rule("DST_ATOP", " S", " D"),
+ new Rule("XOR", " S", "D "), });
+ ruleCombo.addActionListener(event ->
+ {
+ Rule r = (Rule) ruleCombo.getSelectedItem();
+ canvas.setRule(r.getValue());
+ explanation.setText(r.getExplanation());
+ });
+
+ alphaSlider = new JSlider(0, 100, 75);
+ alphaSlider.addChangeListener(event -> canvas.setAlpha(alphaSlider.getValue()));
+ JPanel panel = new JPanel();
+ panel.add(ruleCombo);
+ panel.add(new JLabel("Alpha"));
+ panel.add(alphaSlider);
+ add(panel, BorderLayout.NORTH);
+
+ explanation = new JTextField();
+ add(explanation, BorderLayout.SOUTH);
+
+ canvas.setAlpha(alphaSlider.getValue());
+ Rule r = ruleCombo.getItemAt(ruleCombo.getSelectedIndex());
+ canvas.setRule(r.getValue());
+ explanation.setText(r.getExplanation());
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch11/composite/Rule.java b/corejava第10版/v2ch11/composite/Rule.java
new file mode 100644
index 0000000..1e4f1ce
--- /dev/null
+++ b/corejava第10版/v2ch11/composite/Rule.java
@@ -0,0 +1,66 @@
+package composite;
+
+import java.awt.*;
+
+/**
+ * This class describes a Porter-Duff rule.
+ */
+class Rule
+{
+ private String name;
+ private String porterDuff1;
+ private String porterDuff2;
+
+ /**
+ * Constructs a Porter-Duff rule.
+ * @param n the rule name
+ * @param pd1 the first row of the Porter-Duff square
+ * @param pd2 the second row of the Porter-Duff square
+ */
+ public Rule(String n, String pd1, String pd2)
+ {
+ name = n;
+ porterDuff1 = pd1;
+ porterDuff2 = pd2;
+ }
+
+ /**
+ * Gets an explanation of the behavior of this rule.
+ * @return the explanation
+ */
+ public String getExplanation()
+ {
+ StringBuilder r = new StringBuilder("Source ");
+ if (porterDuff2.equals(" ")) r.append("clears");
+ if (porterDuff2.equals(" S")) r.append("overwrites");
+ if (porterDuff2.equals("DS")) r.append("blends with");
+ if (porterDuff2.equals(" D")) r.append("alpha modifies");
+ if (porterDuff2.equals("D ")) r.append("alpha complement modifies");
+ if (porterDuff2.equals("DD")) r.append("does not affect");
+ r.append(" destination");
+ if (porterDuff1.equals(" S")) r.append(" and overwrites empty pixels");
+ r.append(".");
+ return r.toString();
+ }
+
+ public String toString()
+ {
+ return name;
+ }
+
+ /**
+ * Gets the value of this rule in the AlphaComposite class.
+ * @return the AlphaComposite constant value, or -1 if there is no matching constant
+ */
+ public int getValue()
+ {
+ try
+ {
+ return (Integer) AlphaComposite.class.getField(name).get(null);
+ }
+ catch (Exception e)
+ {
+ return -1;
+ }
+ }
+}
diff --git a/corejava第10版/v2ch11/desktopApp/DesktopAppFrame.java b/corejava第10版/v2ch11/desktopApp/DesktopAppFrame.java
new file mode 100644
index 0000000..227b26f
--- /dev/null
+++ b/corejava第10版/v2ch11/desktopApp/DesktopAppFrame.java
@@ -0,0 +1,144 @@
+package desktopApp;
+
+import java.awt.*;
+import java.io.*;
+import java.net.*;
+
+import javax.swing.*;
+
+class DesktopAppFrame extends JFrame
+{
+ public DesktopAppFrame()
+ {
+ setLayout(new GridBagLayout());
+ final JFileChooser chooser = new JFileChooser();
+ JButton fileChooserButton = new JButton("...");
+ final JTextField fileField = new JTextField(20);
+ fileField.setEditable(false);
+ JButton openButton = new JButton("Open");
+ JButton editButton = new JButton("Edit");
+ JButton printButton = new JButton("Print");
+ final JTextField browseField = new JTextField();
+ JButton browseButton = new JButton("Browse");
+ final JTextField toField = new JTextField();
+ final JTextField subjectField = new JTextField();
+ JButton mailButton = new JButton("Mail");
+
+ openButton.setEnabled(false);
+ editButton.setEnabled(false);
+ printButton.setEnabled(false);
+ browseButton.setEnabled(false);
+ mailButton.setEnabled(false);
+
+ if (Desktop.isDesktopSupported())
+ {
+ Desktop desktop = Desktop.getDesktop();
+ if (desktop.isSupported(Desktop.Action.OPEN)) openButton.setEnabled(true);
+ if (desktop.isSupported(Desktop.Action.EDIT)) editButton.setEnabled(true);
+ if (desktop.isSupported(Desktop.Action.PRINT)) printButton.setEnabled(true);
+ if (desktop.isSupported(Desktop.Action.BROWSE)) browseButton.setEnabled(true);
+ if (desktop.isSupported(Desktop.Action.MAIL)) mailButton.setEnabled(true);
+ }
+
+ fileChooserButton.addActionListener(event ->
+ {
+ if (chooser.showOpenDialog(DesktopAppFrame.this) == JFileChooser.APPROVE_OPTION)
+ fileField.setText(chooser.getSelectedFile().getAbsolutePath());
+ });
+
+ openButton.addActionListener(event ->
+ {
+ try
+ {
+ Desktop.getDesktop().open(chooser.getSelectedFile());
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ });
+
+ editButton.addActionListener(event ->
+ {
+ try
+ {
+ Desktop.getDesktop().edit(chooser.getSelectedFile());
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ });
+
+ printButton.addActionListener(event ->
+ {
+ try
+ {
+ Desktop.getDesktop().print(chooser.getSelectedFile());
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ });
+
+ browseButton.addActionListener(event ->
+ {
+ try
+ {
+ Desktop.getDesktop().browse(new URI(browseField.getText()));
+ }
+ catch (URISyntaxException | IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ });
+
+ mailButton.addActionListener(event ->
+ {
+ try
+ {
+ String subject = percentEncode(subjectField.getText());
+ URI uri = new URI("mailto:" + toField.getText() + "?subject=" + subject);
+
+ System.out.println(uri);
+ Desktop.getDesktop().mail(uri);
+ }
+ catch (URISyntaxException | IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ });
+
+ JPanel buttonPanel = new JPanel();
+ ((FlowLayout) buttonPanel.getLayout()).setHgap(2);
+ buttonPanel.add(openButton);
+ buttonPanel.add(editButton);
+ buttonPanel.add(printButton);
+
+ add(fileChooserButton, new GBC(0, 0).setAnchor(GBC.EAST).setInsets(2));
+ add(fileField, new GBC(1, 0).setFill(GBC.HORIZONTAL));
+ add(buttonPanel, new GBC(2, 0).setAnchor(GBC.WEST).setInsets(0));
+ add(browseField, new GBC(1, 1).setFill(GBC.HORIZONTAL));
+ add(browseButton, new GBC(2, 1).setAnchor(GBC.WEST).setInsets(2));
+ add(new JLabel("To:"), new GBC(0, 2).setAnchor(GBC.EAST).setInsets(5, 2, 5, 2));
+ add(toField, new GBC(1, 2).setFill(GBC.HORIZONTAL));
+ add(mailButton, new GBC(2, 2).setAnchor(GBC.WEST).setInsets(2));
+ add(new JLabel("Subject:"), new GBC(0, 3).setAnchor(GBC.EAST).setInsets(5, 2, 5, 2));
+ add(subjectField, new GBC(1, 3).setFill(GBC.HORIZONTAL));
+
+ pack();
+ }
+
+ private static String percentEncode(String s)
+ {
+ try
+ {
+ return URLEncoder.encode(s, "UTF-8").replaceAll("[+]", "%20");
+ }
+ catch (UnsupportedEncodingException ex)
+ {
+ return null; // UTF-8 is always supported
+ }
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch11/desktopApp/DesktopAppTest.java b/corejava第10版/v2ch11/desktopApp/DesktopAppTest.java
new file mode 100644
index 0000000..67694fd
--- /dev/null
+++ b/corejava第10版/v2ch11/desktopApp/DesktopAppTest.java
@@ -0,0 +1,22 @@
+package desktopApp;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates the desktop app API.
+ * @version 1.01 2016-05-10
+ * @author Cay Horstmann
+ */
+public class DesktopAppTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new DesktopAppFrame();
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch11/desktopApp/GBC.java b/corejava第10版/v2ch11/desktopApp/GBC.java
new file mode 100644
index 0000000..ca8b10d
--- /dev/null
+++ b/corejava第10版/v2ch11/desktopApp/GBC.java
@@ -0,0 +1,131 @@
+package desktopApp;
+
+/*
+GBC - A convenience class to tame the GridBagLayout
+
+Copyright (C) 2002 Cay S. Horstmann (http://horstmann.com)
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+import java.awt.*;
+
+/**
+ This class simplifies the use of the GridBagConstraints
+ class.
+*/
+public class GBC extends GridBagConstraints
+{
+ /**
+ Constructs a GBC with a given gridx and gridy position and
+ all other grid bag constraint values set to the default.
+ @param gridx the gridx position
+ @param gridy the gridy position
+ */
+ public GBC(int gridx, int gridy)
+ {
+ this.gridx = gridx;
+ this.gridy = gridy;
+ }
+
+ /**
+ Constructs a GBC with given gridx, gridy, gridwidth, gridheight
+ and all other grid bag constraint values set to the default.
+ @param gridx the gridx position
+ @param gridy the gridy position
+ @param gridwidth the cell span in x-direction
+ @param gridheight the cell span in y-direction
+ */
+ public GBC(int gridx, int gridy, int gridwidth, int gridheight)
+ {
+ this.gridx = gridx;
+ this.gridy = gridy;
+ this.gridwidth = gridwidth;
+ this.gridheight = gridheight;
+ }
+
+ /**
+ Sets the anchor.
+ @param anchor the anchor value
+ @return this object for further modification
+ */
+ public GBC setAnchor(int anchor)
+ {
+ this.anchor = anchor;
+ return this;
+ }
+
+ /**
+ Sets the fill direction.
+ @param fill the fill direction
+ @return this object for further modification
+ */
+ public GBC setFill(int fill)
+ {
+ this.fill = fill;
+ return this;
+ }
+
+ /**
+ Sets the cell weights.
+ @param weightx the cell weight in x-direction
+ @param weighty the cell weight in y-direction
+ @return this object for further modification
+ */
+ public GBC setWeight(double weightx, double weighty)
+ {
+ this.weightx = weightx;
+ this.weighty = weighty;
+ return this;
+ }
+
+ /**
+ Sets the insets of this cell.
+ @param distance the spacing to use in all directions
+ @return this object for further modification
+ */
+ public GBC setInsets(int distance)
+ {
+ this.insets = new Insets(distance, distance, distance, distance);
+ return this;
+ }
+
+ /**
+ Sets the insets of this cell.
+ @param top the spacing to use on top
+ @param left the spacing to use to the left
+ @param bottom the spacing to use on the bottom
+ @param right the spacing to use to the right
+ @return this object for further modification
+ */
+ public GBC setInsets(int top, int left, int bottom, int right)
+ {
+ this.insets = new Insets(top, left, bottom, right);
+ return this;
+ }
+
+ /**
+ Sets the internal padding
+ @param ipadx the internal padding in x-direction
+ @param ipady the internal padding in y-direction
+ @return this object for further modification
+ */
+ public GBC setIpad(int ipadx, int ipady)
+ {
+ this.ipadx = ipadx;
+ this.ipady = ipady;
+ return this;
+ }
+}
diff --git a/corejava第10版/v2ch11/dnd/SampleComponents.java b/corejava第10版/v2ch11/dnd/SampleComponents.java
new file mode 100644
index 0000000..ca87783
--- /dev/null
+++ b/corejava第10版/v2ch11/dnd/SampleComponents.java
@@ -0,0 +1,59 @@
+package dnd;
+
+import java.awt.*;
+
+import javax.swing.*;
+import javax.swing.tree.*;
+
+public class SampleComponents
+{
+ public static JTree tree()
+ {
+ DefaultMutableTreeNode root = new DefaultMutableTreeNode("World");
+ DefaultMutableTreeNode country = new DefaultMutableTreeNode("USA");
+ root.add(country);
+ DefaultMutableTreeNode state = new DefaultMutableTreeNode("California");
+ country.add(state);
+ DefaultMutableTreeNode city = new DefaultMutableTreeNode("San Jose");
+ state.add(city);
+ city = new DefaultMutableTreeNode("Cupertino");
+ state.add(city);
+ state = new DefaultMutableTreeNode("Michigan");
+ country.add(state);
+ city = new DefaultMutableTreeNode("Ann Arbor");
+ state.add(city);
+ country = new DefaultMutableTreeNode("Germany");
+ root.add(country);
+ state = new DefaultMutableTreeNode("Schleswig-Holstein");
+ country.add(state);
+ city = new DefaultMutableTreeNode("Kiel");
+ state.add(city);
+ return new JTree(root);
+ }
+
+ public static JList list()
+ {
+ String[] words = { "quick", "brown", "hungry", "wild", "silent", "huge", "private",
+ "abstract", "static", "final" };
+
+ DefaultListModel model = new DefaultListModel<>();
+ for (String word : words)
+ model.addElement(word);
+ return new JList<>(model);
+ }
+
+ public static JTable table()
+ {
+ Object[][] cells = { { "Mercury", 2440.0, 0, false, Color.YELLOW },
+ { "Venus", 6052.0, 0, false, Color.YELLOW },
+ { "Earth", 6378.0, 1, false, Color.BLUE }, { "Mars", 3397.0, 2, false, Color.RED },
+ { "Jupiter", 71492.0, 16, true, Color.ORANGE },
+ { "Saturn", 60268.0, 18, true, Color.ORANGE },
+ { "Uranus", 25559.0, 17, true, Color.BLUE },
+ { "Neptune", 24766.0, 8, true, Color.BLUE },
+ { "Pluto", 1137.0, 1, false, Color.BLACK } };
+
+ String[] columnNames = { "Planet", "Radius", "Moons", "Gaseous", "Color" };
+ return new JTable(cells, columnNames);
+ }
+}
diff --git a/corejava第10版/v2ch11/dnd/SwingDnDFrame.java b/corejava第10版/v2ch11/dnd/SwingDnDFrame.java
new file mode 100644
index 0000000..41dddad
--- /dev/null
+++ b/corejava第10版/v2ch11/dnd/SwingDnDFrame.java
@@ -0,0 +1,46 @@
+package dnd;
+
+import java.awt.*;
+
+import javax.swing.*;
+import javax.swing.border.*;
+
+public class SwingDnDFrame extends JFrame
+{
+ public SwingDnDFrame()
+ {
+ JTabbedPane tabbedPane = new JTabbedPane();
+
+ JList list = SampleComponents.list();
+ tabbedPane.addTab("List", list);
+ JTable table = SampleComponents.table();
+ tabbedPane.addTab("Table", table);
+ JTree tree = SampleComponents.tree();
+ tabbedPane.addTab("Tree", tree);
+ JFileChooser fileChooser = new JFileChooser();
+ tabbedPane.addTab("File Chooser", fileChooser);
+ JColorChooser colorChooser = new JColorChooser();
+ tabbedPane.addTab("Color Chooser", colorChooser);
+
+ final JTextArea textArea = new JTextArea(4, 40);
+ JScrollPane scrollPane = new JScrollPane(textArea);
+ scrollPane.setBorder(new TitledBorder(new EtchedBorder(), "Drag text here"));
+
+ JTextField textField = new JTextField("Drag color here");
+ textField.setTransferHandler(new TransferHandler("background"));
+
+ tabbedPane.addChangeListener(event -> textArea.setText(""));
+
+ tree.setDragEnabled(true);
+ table.setDragEnabled(true);
+ list.setDragEnabled(true);
+ fileChooser.setDragEnabled(true);
+ colorChooser.setDragEnabled(true);
+ textField.setDragEnabled(true);
+
+ add(tabbedPane, BorderLayout.NORTH);
+ add(scrollPane, BorderLayout.CENTER);
+ add(textField, BorderLayout.SOUTH);
+ pack();
+ }
+}
diff --git a/corejava第10版/v2ch11/dnd/SwingDnDTest.java b/corejava第10版/v2ch11/dnd/SwingDnDTest.java
new file mode 100644
index 0000000..371e837
--- /dev/null
+++ b/corejava第10版/v2ch11/dnd/SwingDnDTest.java
@@ -0,0 +1,23 @@
+package dnd;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates the basic Swing support for drag and drop.
+ * @version 1.11 2016-05-10
+ * @author Cay Horstmann
+ */
+public class SwingDnDTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new SwingDnDFrame();
+ frame.setTitle("SwingDnDTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch11/dndImage/ImageListDnDFrame.java b/corejava第10版/v2ch11/dndImage/ImageListDnDFrame.java
new file mode 100644
index 0000000..92b818c
--- /dev/null
+++ b/corejava第10版/v2ch11/dndImage/ImageListDnDFrame.java
@@ -0,0 +1,152 @@
+package dndImage;
+
+import java.awt.*;
+import java.awt.datatransfer.*;
+import java.io.*;
+import java.nio.file.*;
+import java.util.*;
+import java.util.List;
+import javax.imageio.*;
+import javax.swing.*;
+
+public class ImageListDnDFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 600;
+ private static final int DEFAULT_HEIGHT = 500;
+
+ private ImageList list1;
+ private ImageList list2;
+
+ public ImageListDnDFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ list1 = new ImageList(Paths.get(getClass().getPackage().getName(), "images1"));
+ list2 = new ImageList(Paths.get(getClass().getPackage().getName(), "images2"));
+
+ setLayout(new GridLayout(2, 1));
+ add(new JScrollPane(list1));
+ add(new JScrollPane(list2));
+ }
+}
+
+class ImageList extends JList
+{
+ public ImageList(Path dir)
+ {
+ DefaultListModel model = new DefaultListModel<>();
+ try (DirectoryStream entries = Files.newDirectoryStream(dir))
+ {
+ for (Path entry : entries)
+ model.addElement(new ImageIcon(entry.toString()));
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+
+ setModel(model);
+ setVisibleRowCount(0);
+ setLayoutOrientation(JList.HORIZONTAL_WRAP);
+ setDragEnabled(true);
+ setDropMode(DropMode.ON_OR_INSERT);
+ setTransferHandler(new ImageListTransferHandler());
+ }
+}
+
+class ImageListTransferHandler extends TransferHandler
+{
+ // support for drag
+
+ public int getSourceActions(JComponent source)
+ {
+ return COPY_OR_MOVE;
+ }
+
+ protected Transferable createTransferable(JComponent source)
+ {
+ ImageList list = (ImageList) source;
+ int index = list.getSelectedIndex();
+ if (index < 0) return null;
+ ImageIcon icon = list.getModel().getElementAt(index);
+ return new ImageTransferable(icon.getImage());
+ }
+
+ protected void exportDone(JComponent source, Transferable data, int action)
+ {
+ if (action == MOVE)
+ {
+ ImageList list = (ImageList) source;
+ int index = list.getSelectedIndex();
+ if (index < 0) return;
+ DefaultListModel> model = (DefaultListModel>) list.getModel();
+ model.remove(index);
+ }
+ }
+
+ // support for drop
+
+ public boolean canImport(TransferSupport support)
+ {
+ if (support.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
+ {
+ if (support.getUserDropAction() == MOVE) support.setDropAction(COPY);
+ return true;
+ }
+ else return support.isDataFlavorSupported(DataFlavor.imageFlavor);
+ }
+
+ public boolean importData(TransferSupport support)
+ {
+ ImageList list = (ImageList) support.getComponent();
+ DefaultListModel model = (DefaultListModel) list.getModel();
+
+ Transferable transferable = support.getTransferable();
+ List flavors = Arrays.asList(transferable.getTransferDataFlavors());
+
+ List images = new ArrayList<>();
+
+ try
+ {
+ if (flavors.contains(DataFlavor.javaFileListFlavor))
+ {
+ @SuppressWarnings("unchecked") List fileList
+ = (List) transferable.getTransferData(DataFlavor.javaFileListFlavor);
+ for (File f : fileList)
+ {
+ try
+ {
+ images.add(ImageIO.read(f));
+ }
+ catch (IOException ex)
+ {
+ // couldn't read image--skip
+ }
+ }
+ }
+ else if (flavors.contains(DataFlavor.imageFlavor))
+ {
+ images.add((Image) transferable.getTransferData(DataFlavor.imageFlavor));
+ }
+
+ int index;
+ if (support.isDrop())
+ {
+ JList.DropLocation location = (JList.DropLocation) support.getDropLocation();
+ index = location.getIndex();
+ if (!location.isInsert()) model.remove(index); // replace location
+ }
+ else index = model.size();
+ for (Image image : images)
+ {
+ model.add(index, new ImageIcon(image));
+ index++;
+ }
+ return true;
+ }
+ catch (IOException | UnsupportedFlavorException ex)
+ {
+ return false;
+ }
+ }
+}
diff --git a/corejava第10版/v2ch11/dndImage/ImageListDnDTest.java b/corejava第10版/v2ch11/dndImage/ImageListDnDTest.java
new file mode 100644
index 0000000..ed881bd
--- /dev/null
+++ b/corejava第10版/v2ch11/dndImage/ImageListDnDTest.java
@@ -0,0 +1,23 @@
+package dndImage;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates drag and drop in an image list.
+ * @version 1.02 2016-05-10
+ * @author Cay Horstmann
+ */
+public class ImageListDnDTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new ImageListDnDFrame();
+ frame.setTitle("ImageListDnDTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
diff --git a/corejava第10版/v2ch11/dndImage/ImageTransferable.java b/corejava第10版/v2ch11/dndImage/ImageTransferable.java
new file mode 100644
index 0000000..615bb8a
--- /dev/null
+++ b/corejava第10版/v2ch11/dndImage/ImageTransferable.java
@@ -0,0 +1,43 @@
+package dndImage;
+
+import java.awt.*;
+import java.awt.datatransfer.*;
+
+/**
+ * This class is a wrapper for the data transfer of image objects.
+ */
+public class ImageTransferable implements Transferable
+{
+ private Image theImage;
+
+ /**
+ * Constructs the selection.
+ * @param image an image
+ */
+ public ImageTransferable(Image image)
+ {
+ theImage = image;
+ }
+
+ public DataFlavor[] getTransferDataFlavors()
+ {
+ return new DataFlavor[] { DataFlavor.imageFlavor };
+ }
+
+ public boolean isDataFlavorSupported(DataFlavor flavor)
+ {
+ return flavor.equals(DataFlavor.imageFlavor);
+ }
+
+ public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException
+ {
+ if (flavor.equals(DataFlavor.imageFlavor))
+ {
+ return theImage;
+ }
+ else
+ {
+ throw new UnsupportedFlavorException(flavor);
+ }
+ }
+}
diff --git a/corejava第10版/v2ch11/dndImage/images1/Jupiter.gif b/corejava第10版/v2ch11/dndImage/images1/Jupiter.gif
new file mode 100644
index 0000000..32d271d
Binary files /dev/null and b/corejava第10版/v2ch11/dndImage/images1/Jupiter.gif differ
diff --git a/corejava第10版/v2ch11/dndImage/images1/Mars.gif b/corejava第10版/v2ch11/dndImage/images1/Mars.gif
new file mode 100644
index 0000000..234d36f
Binary files /dev/null and b/corejava第10版/v2ch11/dndImage/images1/Mars.gif differ
diff --git a/corejava第10版/v2ch11/dndImage/images1/Mercury.gif b/corejava第10版/v2ch11/dndImage/images1/Mercury.gif
new file mode 100644
index 0000000..9fd78a5
Binary files /dev/null and b/corejava第10版/v2ch11/dndImage/images1/Mercury.gif differ
diff --git a/corejava第10版/v2ch11/dndImage/images1/Neptune.gif b/corejava第10版/v2ch11/dndImage/images1/Neptune.gif
new file mode 100644
index 0000000..33b18f2
Binary files /dev/null and b/corejava第10版/v2ch11/dndImage/images1/Neptune.gif differ
diff --git a/corejava第10版/v2ch11/dndImage/images1/Pluto.gif b/corejava第10版/v2ch11/dndImage/images1/Pluto.gif
new file mode 100644
index 0000000..3909638
Binary files /dev/null and b/corejava第10版/v2ch11/dndImage/images1/Pluto.gif differ
diff --git a/corejava第10版/v2ch11/dndImage/images1/Uranus.gif b/corejava第10版/v2ch11/dndImage/images1/Uranus.gif
new file mode 100644
index 0000000..e9baa5d
Binary files /dev/null and b/corejava第10版/v2ch11/dndImage/images1/Uranus.gif differ
diff --git a/corejava第10版/v2ch11/dndImage/images1/Venus.gif b/corejava第10版/v2ch11/dndImage/images1/Venus.gif
new file mode 100644
index 0000000..8552313
Binary files /dev/null and b/corejava第10版/v2ch11/dndImage/images1/Venus.gif differ
diff --git a/corejava第10版/v2ch11/dndImage/images2/Earth.gif b/corejava第10版/v2ch11/dndImage/images2/Earth.gif
new file mode 100644
index 0000000..5982457
Binary files /dev/null and b/corejava第10版/v2ch11/dndImage/images2/Earth.gif differ
diff --git a/corejava第10版/v2ch11/dndImage/images2/Saturn.gif b/corejava第10版/v2ch11/dndImage/images2/Saturn.gif
new file mode 100644
index 0000000..b4c6144
Binary files /dev/null and b/corejava第10版/v2ch11/dndImage/images2/Saturn.gif differ
diff --git a/corejava第10版/v2ch11/imageIO/ImageIOFrame.java b/corejava第10版/v2ch11/imageIO/ImageIOFrame.java
new file mode 100644
index 0000000..ce4c802
--- /dev/null
+++ b/corejava第10版/v2ch11/imageIO/ImageIOFrame.java
@@ -0,0 +1,148 @@
+package imageIO;
+
+import java.awt.image.*;
+import java.io.*;
+import java.util.*;
+
+import javax.imageio.*;
+import javax.imageio.stream.*;
+import javax.swing.*;
+import javax.swing.filechooser.*;
+
+/**
+ * This frame displays the loaded images. The menu has items for loading and saving files.
+ */
+public class ImageIOFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 400;
+ private static final int DEFAULT_HEIGHT = 400;
+
+ private static Set writerFormats = getWriterFormats();
+
+ private BufferedImage[] images;
+
+ public ImageIOFrame()
+ {
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ JMenu fileMenu = new JMenu("File");
+ JMenuItem openItem = new JMenuItem("Open");
+ openItem.addActionListener(event -> openFile());
+ fileMenu.add(openItem);
+
+ JMenu saveMenu = new JMenu("Save");
+ fileMenu.add(saveMenu);
+ Iterator iter = writerFormats.iterator();
+ while (iter.hasNext())
+ {
+ final String formatName = iter.next();
+ JMenuItem formatItem = new JMenuItem(formatName);
+ saveMenu.add(formatItem);
+ formatItem.addActionListener(event -> saveFile(formatName));
+ }
+
+ JMenuItem exitItem = new JMenuItem("Exit");
+ exitItem.addActionListener(event -> System.exit(0));
+ fileMenu.add(exitItem);
+
+ JMenuBar menuBar = new JMenuBar();
+ menuBar.add(fileMenu);
+ setJMenuBar(menuBar);
+ }
+
+ /**
+ * Open a file and load the images.
+ */
+ public void openFile()
+ {
+ JFileChooser chooser = new JFileChooser();
+ chooser.setCurrentDirectory(new File("."));
+ String[] extensions = ImageIO.getReaderFileSuffixes();
+ chooser.setFileFilter(new FileNameExtensionFilter("Image files", extensions));
+ int r = chooser.showOpenDialog(this);
+ if (r != JFileChooser.APPROVE_OPTION) return;
+ File f = chooser.getSelectedFile();
+ Box box = Box.createVerticalBox();
+ try
+ {
+ String name = f.getName();
+ String suffix = name.substring(name.lastIndexOf('.') + 1);
+ Iterator iter = ImageIO.getImageReadersBySuffix(suffix);
+ ImageReader reader = iter.next();
+ ImageInputStream imageIn = ImageIO.createImageInputStream(f);
+ reader.setInput(imageIn);
+ int count = reader.getNumImages(true);
+ images = new BufferedImage[count];
+ for (int i = 0; i < count; i++)
+ {
+ images[i] = reader.read(i);
+ box.add(new JLabel(new ImageIcon(images[i])));
+ }
+ }
+ catch (IOException e)
+ {
+ JOptionPane.showMessageDialog(this, e);
+ }
+ setContentPane(new JScrollPane(box));
+ validate();
+ }
+
+ /**
+ * Save the current image in a file.
+ * @param formatName the file format
+ */
+ public void saveFile(final String formatName)
+ {
+ if (images == null) return;
+ Iterator iter = ImageIO.getImageWritersByFormatName(formatName);
+ ImageWriter writer = iter.next();
+ JFileChooser chooser = new JFileChooser();
+ chooser.setCurrentDirectory(new File("."));
+ String[] extensions = writer.getOriginatingProvider().getFileSuffixes();
+ chooser.setFileFilter(new FileNameExtensionFilter("Image files", extensions));
+
+ int r = chooser.showSaveDialog(this);
+ if (r != JFileChooser.APPROVE_OPTION) return;
+ File f = chooser.getSelectedFile();
+ try
+ {
+ ImageOutputStream imageOut = ImageIO.createImageOutputStream(f);
+ writer.setOutput(imageOut);
+
+ writer.write(new IIOImage(images[0], null, null));
+ for (int i = 1; i < images.length; i++)
+ {
+ IIOImage iioImage = new IIOImage(images[i], null, null);
+ if (writer.canInsertImage(i)) writer.writeInsert(i, iioImage, null);
+ }
+ }
+ catch (IOException e)
+ {
+ JOptionPane.showMessageDialog(this, e);
+ }
+ }
+
+ /**
+ * Gets a set of "preferred" format names of all image writers. The preferred format name is the
+ * first format name that a writer specifies.
+ * @return the format name set
+ */
+ public static Set getWriterFormats()
+ {
+ Set writerFormats = new TreeSet<>();
+ Set formatNames = new TreeSet<>(
+ Arrays.asList(ImageIO.getWriterFormatNames()));
+ while (formatNames.size() > 0)
+ {
+ String name = formatNames.iterator().next();
+ Iterator iter = ImageIO.getImageWritersByFormatName(name);
+ ImageWriter writer = iter.next();
+ String[] names = writer.getOriginatingProvider().getFormatNames();
+ String format = names[0];
+ if (format.equals(format.toLowerCase())) format = format.toUpperCase();
+ writerFormats.add(format);
+ formatNames.removeAll(Arrays.asList(names));
+ }
+ return writerFormats;
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch11/imageIO/ImageIOTest.java b/corejava第10版/v2ch11/imageIO/ImageIOTest.java
new file mode 100644
index 0000000..08d9432
--- /dev/null
+++ b/corejava第10版/v2ch11/imageIO/ImageIOTest.java
@@ -0,0 +1,24 @@
+package imageIO;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program lets you read and write image files in the formats that the JDK supports. Multi-file
+ * images are supported.
+ * @version 1.04 2016-05-10
+ * @author Cay Horstmann
+ */
+public class ImageIOTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new ImageIOFrame();
+ frame.setTitle("CompositeTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/javacore第11版/corejava/v2ch11/imageIO/e-mail.gif b/corejava第10版/v2ch11/imageIO/e-mail.gif
similarity index 100%
rename from javacore第11版/corejava/v2ch11/imageIO/e-mail.gif
rename to corejava第10版/v2ch11/imageIO/e-mail.gif
diff --git a/corejava第10版/v2ch11/imageProcessing/ImageProcessingFrame.java b/corejava第10版/v2ch11/imageProcessing/ImageProcessingFrame.java
new file mode 100644
index 0000000..a4b0c4e
--- /dev/null
+++ b/corejava第10版/v2ch11/imageProcessing/ImageProcessingFrame.java
@@ -0,0 +1,160 @@
+package imageProcessing;
+
+import java.awt.*;
+import java.awt.geom.*;
+import java.awt.image.*;
+import java.io.*;
+
+import javax.imageio.*;
+import javax.swing.*;
+import javax.swing.filechooser.*;
+
+/**
+ * This frame has a menu to load an image and to specify various transformations, and a component to
+ * show the resulting image.
+ */
+public class ImageProcessingFrame extends JFrame
+{
+ private static final int DEFAULT_WIDTH = 400;
+ private static final int DEFAULT_HEIGHT = 400;
+
+ private BufferedImage image;
+
+ public ImageProcessingFrame()
+ {
+ setTitle("ImageProcessingTest");
+ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+
+ add(new JComponent()
+ {
+ public void paintComponent(Graphics g)
+ {
+ if (image != null) g.drawImage(image, 0, 0, null);
+ }
+ });
+
+ JMenu fileMenu = new JMenu("File");
+ JMenuItem openItem = new JMenuItem("Open");
+ openItem.addActionListener(event -> openFile());
+ fileMenu.add(openItem);
+
+ JMenuItem exitItem = new JMenuItem("Exit");
+ exitItem.addActionListener(event -> System.exit(0));
+ fileMenu.add(exitItem);
+
+ JMenu editMenu = new JMenu("Edit");
+ JMenuItem blurItem = new JMenuItem("Blur");
+ blurItem.addActionListener(event ->
+ {
+ float weight = 1.0f / 9.0f;
+ float[] elements = new float[9];
+ for (int i = 0; i < 9; i++)
+ elements[i] = weight;
+ convolve(elements);
+ });
+ editMenu.add(blurItem);
+
+ JMenuItem sharpenItem = new JMenuItem("Sharpen");
+ sharpenItem.addActionListener(event ->
+ {
+ float[] elements = { 0.0f, -1.0f, 0.0f, -1.0f, 5.f, -1.0f, 0.0f, -1.0f, 0.0f };
+ convolve(elements);
+ });
+ editMenu.add(sharpenItem);
+
+ JMenuItem brightenItem = new JMenuItem("Brighten");
+ brightenItem.addActionListener(event ->
+ {
+ float a = 1.1f;
+ float b = 20.0f;
+ RescaleOp op = new RescaleOp(a, b, null);
+ filter(op);
+ });
+ editMenu.add(brightenItem);
+
+ JMenuItem edgeDetectItem = new JMenuItem("Edge detect");
+ edgeDetectItem.addActionListener(event ->
+ {
+ float[] elements = { 0.0f, -1.0f, 0.0f, -1.0f, 4.f, -1.0f, 0.0f, -1.0f, 0.0f };
+ convolve(elements);
+ });
+ editMenu.add(edgeDetectItem);
+
+ JMenuItem negativeItem = new JMenuItem("Negative");
+ negativeItem.addActionListener(event ->
+ {
+ short[] negative = new short[256 * 1];
+ for (int i = 0; i < 256; i++)
+ negative[i] = (short) (255 - i);
+ ShortLookupTable table = new ShortLookupTable(0, negative);
+ LookupOp op = new LookupOp(table, null);
+ filter(op);
+ });
+ editMenu.add(negativeItem);
+
+ JMenuItem rotateItem = new JMenuItem("Rotate");
+ rotateItem.addActionListener(event ->
+ {
+ if (image == null) return;
+ AffineTransform transform = AffineTransform.getRotateInstance(Math.toRadians(5),
+ image.getWidth() / 2, image.getHeight() / 2);
+ AffineTransformOp op = new AffineTransformOp(transform,
+ AffineTransformOp.TYPE_BICUBIC);
+ filter(op);
+ });
+ editMenu.add(rotateItem);
+
+ JMenuBar menuBar = new JMenuBar();
+ menuBar.add(fileMenu);
+ menuBar.add(editMenu);
+ setJMenuBar(menuBar);
+ }
+
+ /**
+ * Open a file and load the image.
+ */
+ public void openFile()
+ {
+ JFileChooser chooser = new JFileChooser(".");
+ chooser.setCurrentDirectory(new File(getClass().getPackage().getName()));
+ String[] extensions = ImageIO.getReaderFileSuffixes();
+ chooser.setFileFilter(new FileNameExtensionFilter("Image files", extensions));
+ int r = chooser.showOpenDialog(this);
+ if (r != JFileChooser.APPROVE_OPTION) return;
+
+ try
+ {
+ Image img = ImageIO.read(chooser.getSelectedFile());
+ image = new BufferedImage(img.getWidth(null), img.getHeight(null),
+ BufferedImage.TYPE_INT_RGB);
+ image.getGraphics().drawImage(img, 0, 0, null);
+ }
+ catch (IOException e)
+ {
+ JOptionPane.showMessageDialog(this, e);
+ }
+ repaint();
+ }
+
+ /**
+ * Apply a filter and repaint.
+ * @param op the image operation to apply
+ */
+ private void filter(BufferedImageOp op)
+ {
+ if (image == null) return;
+ image = op.filter(image, null);
+ repaint();
+ }
+
+ /**
+ * Apply a convolution and repaint.
+ * @param elements the convolution kernel (an array of 9 matrix elements)
+ */
+ private void convolve(float[] elements)
+ {
+ Kernel kernel = new Kernel(3, 3, elements);
+ ConvolveOp op = new ConvolveOp(kernel);
+ filter(op);
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch11/imageProcessing/ImageProcessingTest.java b/corejava第10版/v2ch11/imageProcessing/ImageProcessingTest.java
new file mode 100644
index 0000000..b8f624c
--- /dev/null
+++ b/corejava第10版/v2ch11/imageProcessing/ImageProcessingTest.java
@@ -0,0 +1,22 @@
+package imageProcessing;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates various image processing operations.
+ * @version 1.04 2016-05-10
+ * @author Cay Horstmann
+ */
+public class ImageProcessingTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new ImageProcessingFrame();
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch11/imageTransfer/ImageTransferFrame.java b/corejava第10版/v2ch11/imageTransfer/ImageTransferFrame.java
new file mode 100644
index 0000000..e5a7015
--- /dev/null
+++ b/corejava第10版/v2ch11/imageTransfer/ImageTransferFrame.java
@@ -0,0 +1,76 @@
+package imageTransfer;
+
+import java.awt.*;
+import java.awt.datatransfer.*;
+import java.awt.image.*;
+import java.io.*;
+
+import javax.swing.*;
+
+/**
+ * This frame has an image label and buttons for copying and pasting an image.
+ */
+class ImageTransferFrame extends JFrame
+{
+ private JLabel label;
+ private Image image;
+ private static final int IMAGE_WIDTH = 300;
+ private static final int IMAGE_HEIGHT = 300;
+
+ public ImageTransferFrame()
+ {
+ label = new JLabel();
+ image = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_ARGB);
+ Graphics g = image.getGraphics();
+ g.setColor(Color.WHITE);
+ g.fillRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);
+ g.setColor(Color.RED);
+ g.fillOval(IMAGE_WIDTH / 4, IMAGE_WIDTH / 4, IMAGE_WIDTH / 2, IMAGE_HEIGHT / 2);
+
+ label.setIcon(new ImageIcon(image));
+ add(new JScrollPane(label), BorderLayout.CENTER);
+ JPanel panel = new JPanel();
+
+ JButton copyButton = new JButton("Copy");
+ panel.add(copyButton);
+ copyButton.addActionListener(event -> copy());
+
+ JButton pasteButton = new JButton("Paste");
+ panel.add(pasteButton);
+ pasteButton.addActionListener(event -> paste());
+
+ add(panel, BorderLayout.SOUTH);
+ pack();
+ }
+
+ /**
+ * Copies the current image to the system clipboard.
+ */
+ private void copy()
+ {
+ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ ImageTransferable selection = new ImageTransferable(image);
+ clipboard.setContents(selection, null);
+ }
+
+ /**
+ * Pastes the image from the system clipboard into the image label.
+ */
+ private void paste()
+ {
+ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ DataFlavor flavor = DataFlavor.imageFlavor;
+ if (clipboard.isDataFlavorAvailable(flavor))
+ {
+ try
+ {
+ image = (Image) clipboard.getData(flavor);
+ label.setIcon(new ImageIcon(image));
+ }
+ catch (UnsupportedFlavorException | IOException ex)
+ {
+ JOptionPane.showMessageDialog(this, ex);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch11/imageTransfer/ImageTransferTest.java b/corejava第10版/v2ch11/imageTransfer/ImageTransferTest.java
new file mode 100644
index 0000000..4fc24ac
--- /dev/null
+++ b/corejava第10版/v2ch11/imageTransfer/ImageTransferTest.java
@@ -0,0 +1,25 @@
+package imageTransfer;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates the transfer of images between a Java application and the system
+ * clipboard.
+ * @version 1.23 2016-05-10
+ * @author Cay Horstmann
+ */
+public class ImageTransferTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new ImageTransferFrame();
+ frame.setTitle("ImageTransferTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
diff --git a/corejava第10版/v2ch11/imageTransfer/ImageTransferable.java b/corejava第10版/v2ch11/imageTransfer/ImageTransferable.java
new file mode 100644
index 0000000..819ead5
--- /dev/null
+++ b/corejava第10版/v2ch11/imageTransfer/ImageTransferable.java
@@ -0,0 +1,43 @@
+package imageTransfer;
+
+import java.awt.*;
+import java.awt.datatransfer.*;
+
+/**
+ * This class is a wrapper for the data transfer of image objects.
+ */
+public class ImageTransferable implements Transferable
+{
+ private Image theImage;
+
+ /**
+ * Constructs the selection.
+ * @param image an image
+ */
+ public ImageTransferable(Image image)
+ {
+ theImage = image;
+ }
+
+ public DataFlavor[] getTransferDataFlavors()
+ {
+ return new DataFlavor[] { DataFlavor.imageFlavor };
+ }
+
+ public boolean isDataFlavorSupported(DataFlavor flavor)
+ {
+ return flavor.equals(DataFlavor.imageFlavor);
+ }
+
+ public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException
+ {
+ if (flavor.equals(DataFlavor.imageFlavor))
+ {
+ return theImage;
+ }
+ else
+ {
+ throw new UnsupportedFlavorException(flavor);
+ }
+ }
+}
diff --git a/corejava第10版/v2ch11/print/PrintComponent.java b/corejava第10版/v2ch11/print/PrintComponent.java
new file mode 100644
index 0000000..972e597
--- /dev/null
+++ b/corejava第10版/v2ch11/print/PrintComponent.java
@@ -0,0 +1,67 @@
+package print;
+
+import java.awt.*;
+import java.awt.font.*;
+import java.awt.geom.*;
+import java.awt.print.*;
+import javax.swing.*;
+
+/**
+ * This component generates a 2D graphics image for screen display and printing.
+ */
+public class PrintComponent extends JComponent implements Printable
+{
+ private static final Dimension PREFERRED_SIZE = new Dimension(300, 300);
+ public void paintComponent(Graphics g)
+ {
+ Graphics2D g2 = (Graphics2D) g;
+ drawPage(g2);
+ }
+
+ public int print(Graphics g, PageFormat pf, int page) throws PrinterException
+ {
+ if (page >= 1) return Printable.NO_SUCH_PAGE;
+ Graphics2D g2 = (Graphics2D) g;
+ g2.translate(pf.getImageableX(), pf.getImageableY());
+ g2.draw(new Rectangle2D.Double(0, 0, pf.getImageableWidth(), pf.getImageableHeight()));
+
+ drawPage(g2);
+ return Printable.PAGE_EXISTS;
+ }
+
+ /**
+ * This method draws the page both on the screen and the printer graphics context.
+ * @param g2 the graphics context
+ */
+ public void drawPage(Graphics2D g2)
+ {
+ FontRenderContext context = g2.getFontRenderContext();
+ Font f = new Font("Serif", Font.PLAIN, 72);
+ GeneralPath clipShape = new GeneralPath();
+
+ TextLayout layout = new TextLayout("Hello", f, context);
+ AffineTransform transform = AffineTransform.getTranslateInstance(0, 72);
+ Shape outline = layout.getOutline(transform);
+ clipShape.append(outline, false);
+
+ layout = new TextLayout("World", f, context);
+ transform = AffineTransform.getTranslateInstance(0, 144);
+ outline = layout.getOutline(transform);
+ clipShape.append(outline, false);
+
+ g2.draw(clipShape);
+ g2.clip(clipShape);
+
+ final int NLINES = 50;
+ Point2D p = new Point2D.Double(0, 0);
+ for (int i = 0; i < NLINES; i++)
+ {
+ double x = (2 * getWidth() * i) / NLINES;
+ double y = (2 * getHeight() * (NLINES - 1 - i)) / NLINES;
+ Point2D q = new Point2D.Double(x, y);
+ g2.draw(new Line2D.Double(p, q));
+ }
+ }
+
+ public Dimension getPreferredSize() { return PREFERRED_SIZE; }
+}
diff --git a/corejava第10版/v2ch11/print/PrintTest.java b/corejava第10版/v2ch11/print/PrintTest.java
new file mode 100644
index 0000000..29b300d
--- /dev/null
+++ b/corejava第10版/v2ch11/print/PrintTest.java
@@ -0,0 +1,23 @@
+package print;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates how to print 2D graphics
+ * @version 1.13 2016-05-10
+ * @author Cay Horstmann
+ */
+public class PrintTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new PrintTestFrame();
+ frame.setTitle("PrintTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch11/print/PrintTestFrame.java b/corejava第10版/v2ch11/print/PrintTestFrame.java
new file mode 100644
index 0000000..21a0dc3
--- /dev/null
+++ b/corejava第10版/v2ch11/print/PrintTestFrame.java
@@ -0,0 +1,53 @@
+package print;
+
+import java.awt.*;
+import java.awt.print.*;
+
+import javax.print.attribute.*;
+import javax.swing.*;
+
+/**
+ * This frame shows a panel with 2D graphics and buttons to print the graphics and to set up the
+ * page format.
+ */
+public class PrintTestFrame extends JFrame
+{
+ private PrintComponent canvas;
+ private PrintRequestAttributeSet attributes;
+
+ public PrintTestFrame()
+ {
+ canvas = new PrintComponent();
+ add(canvas, BorderLayout.CENTER);
+
+ attributes = new HashPrintRequestAttributeSet();
+
+ JPanel buttonPanel = new JPanel();
+ JButton printButton = new JButton("Print");
+ buttonPanel.add(printButton);
+ printButton.addActionListener(event ->
+ {
+ try
+ {
+ PrinterJob job = PrinterJob.getPrinterJob();
+ job.setPrintable(canvas);
+ if (job.printDialog(attributes)) job.print(attributes);
+ }
+ catch (PrinterException ex)
+ {
+ JOptionPane.showMessageDialog(PrintTestFrame.this, ex);
+ }
+ });
+
+ JButton pageSetupButton = new JButton("Page setup");
+ buttonPanel.add(pageSetupButton);
+ pageSetupButton.addActionListener(event ->
+ {
+ PrinterJob job = PrinterJob.getPrinterJob();
+ job.pageDialog(attributes);
+ });
+
+ add(buttonPanel, BorderLayout.NORTH);
+ pack();
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch11/printService/PrintServiceTest.java b/corejava第10版/v2ch11/printService/PrintServiceTest.java
new file mode 100644
index 0000000..abfe2f7
--- /dev/null
+++ b/corejava第10版/v2ch11/printService/PrintServiceTest.java
@@ -0,0 +1,46 @@
+package printService;
+
+import java.io.*;
+import java.nio.file.*;
+import javax.print.*;
+
+/**
+ * This program demonstrates the use of print services. The program lets you print a GIF image to
+ * any of the print services that support the GIF document flavor.
+ * @version 1.10 2007-08-16
+ * @author Cay Horstmann
+ */
+public class PrintServiceTest
+{
+ public static void main(String[] args)
+ {
+ DocFlavor flavor = DocFlavor.URL.GIF;
+ PrintService[] services = PrintServiceLookup.lookupPrintServices(flavor, null);
+ if (args.length == 0)
+ {
+ if (services.length == 0) System.out.println("No printer for flavor " + flavor);
+ else
+ {
+ System.out.println("Specify a file of flavor " + flavor
+ + "\nand optionally the number of the desired printer.");
+ for (int i = 0; i < services.length; i++)
+ System.out.println((i + 1) + ": " + services[i].getName());
+ }
+ System.exit(0);
+ }
+ String fileName = args[0];
+ int p = 1;
+ if (args.length > 1) p = Integer.parseInt(args[1]);
+ if (fileName == null) return;
+ try (InputStream in = Files.newInputStream(Paths.get(fileName)))
+ {
+ Doc doc = new SimpleDoc(in, flavor, null);
+ DocPrintJob job = services[p - 1].createPrintJob();
+ job.print(doc, null);
+ }
+ catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch11/rasterImage/RasterImageFrame.java b/corejava第10版/v2ch11/rasterImage/RasterImageFrame.java
new file mode 100644
index 0000000..551fdcf
--- /dev/null
+++ b/corejava第10版/v2ch11/rasterImage/RasterImageFrame.java
@@ -0,0 +1,68 @@
+package rasterImage;
+
+import java.awt.*;
+import java.awt.image.*;
+import javax.swing.*;
+
+/**
+ * This frame shows an image with a Mandelbrot set.
+ */
+public class RasterImageFrame extends JFrame
+{
+ private static final double XMIN = -2;
+ private static final double XMAX = 2;
+ private static final double YMIN = -2;
+ private static final double YMAX = 2;
+ private static final int MAX_ITERATIONS = 16;
+ private static final int IMAGE_WIDTH = 400;
+ private static final int IMAGE_HEIGHT = 400;
+
+ public RasterImageFrame()
+ {
+ BufferedImage image = makeMandelbrot(IMAGE_WIDTH, IMAGE_HEIGHT);
+ add(new JLabel(new ImageIcon(image)));
+ pack();
+ }
+
+ /**
+ * Makes the Mandelbrot image.
+ * @param width the width
+ * @parah height the height
+ * @return the image
+ */
+ public BufferedImage makeMandelbrot(int width, int height)
+ {
+ BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
+ WritableRaster raster = image.getRaster();
+ ColorModel model = image.getColorModel();
+
+ Color fractalColor = Color.red;
+ int argb = fractalColor.getRGB();
+ Object colorData = model.getDataElements(argb, null);
+
+ for (int i = 0; i < width; i++)
+ for (int j = 0; j < height; j++)
+ {
+ double a = XMIN + i * (XMAX - XMIN) / width;
+ double b = YMIN + j * (YMAX - YMIN) / height;
+ if (!escapesToInfinity(a, b)) raster.setDataElements(i, j, colorData);
+ }
+ return image;
+ }
+
+ private boolean escapesToInfinity(double a, double b)
+ {
+ double x = 0.0;
+ double y = 0.0;
+ int iterations = 0;
+ while (x <= 2 && y <= 2 && iterations < MAX_ITERATIONS)
+ {
+ double xnew = x * x - y * y + a;
+ double ynew = 2 * x * y + b;
+ x = xnew;
+ y = ynew;
+ iterations++;
+ }
+ return x > 2 || y > 2;
+ }
+}
diff --git a/corejava第10版/v2ch11/rasterImage/RasterImageTest.java b/corejava第10版/v2ch11/rasterImage/RasterImageTest.java
new file mode 100644
index 0000000..b33e219
--- /dev/null
+++ b/corejava第10版/v2ch11/rasterImage/RasterImageTest.java
@@ -0,0 +1,23 @@
+package rasterImage;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates how to build up an image from individual pixels.
+ * @version 1.14 2016-05-10
+ * @author Cay Horstmann
+ */
+public class RasterImageTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new RasterImageFrame();
+ frame.setTitle("RasterImageTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch11/renderQuality/GBC.java b/corejava第10版/v2ch11/renderQuality/GBC.java
new file mode 100644
index 0000000..d011b9f
--- /dev/null
+++ b/corejava第10版/v2ch11/renderQuality/GBC.java
@@ -0,0 +1,131 @@
+package renderQuality;
+
+/*
+GBC - A convenience class to tame the GridBagLayout
+
+Copyright (C) 2002 Cay S. Horstmann (http://horstmann.com)
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+import java.awt.*;
+
+/**
+ This class simplifies the use of the GridBagConstraints
+ class.
+*/
+public class GBC extends GridBagConstraints
+{
+ /**
+ Constructs a GBC with a given gridx and gridy position and
+ all other grid bag constraint values set to the default.
+ @param gridx the gridx position
+ @param gridy the gridy position
+ */
+ public GBC(int gridx, int gridy)
+ {
+ this.gridx = gridx;
+ this.gridy = gridy;
+ }
+
+ /**
+ Constructs a GBC with given gridx, gridy, gridwidth, gridheight
+ and all other grid bag constraint values set to the default.
+ @param gridx the gridx position
+ @param gridy the gridy position
+ @param gridwidth the cell span in x-direction
+ @param gridheight the cell span in y-direction
+ */
+ public GBC(int gridx, int gridy, int gridwidth, int gridheight)
+ {
+ this.gridx = gridx;
+ this.gridy = gridy;
+ this.gridwidth = gridwidth;
+ this.gridheight = gridheight;
+ }
+
+ /**
+ Sets the anchor.
+ @param anchor the anchor value
+ @return this object for further modification
+ */
+ public GBC setAnchor(int anchor)
+ {
+ this.anchor = anchor;
+ return this;
+ }
+
+ /**
+ Sets the fill direction.
+ @param fill the fill direction
+ @return this object for further modification
+ */
+ public GBC setFill(int fill)
+ {
+ this.fill = fill;
+ return this;
+ }
+
+ /**
+ Sets the cell weights.
+ @param weightx the cell weight in x-direction
+ @param weighty the cell weight in y-direction
+ @return this object for further modification
+ */
+ public GBC setWeight(double weightx, double weighty)
+ {
+ this.weightx = weightx;
+ this.weighty = weighty;
+ return this;
+ }
+
+ /**
+ Sets the insets of this cell.
+ @param distance the spacing to use in all directions
+ @return this object for further modification
+ */
+ public GBC setInsets(int distance)
+ {
+ this.insets = new Insets(distance, distance, distance, distance);
+ return this;
+ }
+
+ /**
+ Sets the insets of this cell.
+ @param top the spacing to use on top
+ @param left the spacing to use to the left
+ @param bottom the spacing to use on the bottom
+ @param right the spacing to use to the right
+ @return this object for further modification
+ */
+ public GBC setInsets(int top, int left, int bottom, int right)
+ {
+ this.insets = new Insets(top, left, bottom, right);
+ return this;
+ }
+
+ /**
+ Sets the internal padding
+ @param ipadx the internal padding in x-direction
+ @param ipady the internal padding in y-direction
+ @return this object for further modification
+ */
+ public GBC setIpad(int ipadx, int ipady)
+ {
+ this.ipadx = ipadx;
+ this.ipady = ipady;
+ return this;
+ }
+}
diff --git a/corejava第10版/v2ch11/renderQuality/RenderQualityTest.java b/corejava第10版/v2ch11/renderQuality/RenderQualityTest.java
new file mode 100644
index 0000000..567b5a7
--- /dev/null
+++ b/corejava第10版/v2ch11/renderQuality/RenderQualityTest.java
@@ -0,0 +1,23 @@
+package renderQuality;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates the effect of the various rendering hints.
+ * @version 1.11 2016-05-10
+ * @author Cay Horstmann
+ */
+public class RenderQualityTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new RenderQualityTestFrame();
+ frame.setTitle("RenderQualityTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch11/renderQuality/RenderQualityTestFrame.java b/corejava第10版/v2ch11/renderQuality/RenderQualityTestFrame.java
new file mode 100644
index 0000000..66217fe
--- /dev/null
+++ b/corejava第10版/v2ch11/renderQuality/RenderQualityTestFrame.java
@@ -0,0 +1,125 @@
+package renderQuality;
+
+import java.awt.*;
+import java.awt.geom.*;
+
+import javax.swing.*;
+
+/**
+ * This frame contains buttons to set rendering hints and an image that is drawn with the selected
+ * hints.
+ */
+public class RenderQualityTestFrame extends JFrame
+{
+ private RenderQualityComponent canvas;
+ private JPanel buttonBox;
+ private RenderingHints hints;
+ private int r;
+
+ public RenderQualityTestFrame()
+ {
+ buttonBox = new JPanel();
+ buttonBox.setLayout(new GridBagLayout());
+ hints = new RenderingHints(null);
+
+ makeButtons("KEY_ANTIALIASING", "VALUE_ANTIALIAS_OFF", "VALUE_ANTIALIAS_ON");
+ makeButtons("KEY_TEXT_ANTIALIASING", "VALUE_TEXT_ANTIALIAS_OFF", "VALUE_TEXT_ANTIALIAS_ON");
+ makeButtons("KEY_FRACTIONALMETRICS", "VALUE_FRACTIONALMETRICS_OFF",
+ "VALUE_FRACTIONALMETRICS_ON");
+ makeButtons("KEY_RENDERING", "VALUE_RENDER_SPEED", "VALUE_RENDER_QUALITY");
+ makeButtons("KEY_STROKE_CONTROL", "VALUE_STROKE_PURE", "VALUE_STROKE_NORMALIZE");
+ canvas = new RenderQualityComponent();
+ canvas.setRenderingHints(hints);
+
+ add(canvas, BorderLayout.CENTER);
+ add(buttonBox, BorderLayout.NORTH);
+ pack();
+ }
+
+ /**
+ * Makes a set of buttons for a rendering hint key and values.
+ * @param key the key name
+ * @param value1 the name of the first value for the key
+ * @param value2 the name of the second value for the key
+ */
+ void makeButtons(String key, String value1, String value2)
+ {
+ try
+ {
+ final RenderingHints.Key k =
+ (RenderingHints.Key) RenderingHints.class.getField(key).get(null);
+ final Object v1 = RenderingHints.class.getField(value1).get(null);
+ final Object v2 = RenderingHints.class.getField(value2).get(null);
+ JLabel label = new JLabel(key);
+
+ buttonBox.add(label, new GBC(0, r).setAnchor(GBC.WEST));
+ ButtonGroup group = new ButtonGroup();
+ JRadioButton b1 = new JRadioButton(value1, true);
+
+ buttonBox.add(b1, new GBC(1, r).setAnchor(GBC.WEST));
+ group.add(b1);
+ b1.addActionListener(event ->
+ {
+ hints.put(k, v1);
+ canvas.setRenderingHints(hints);
+ });
+ JRadioButton b2 = new JRadioButton(value2, false);
+
+ buttonBox.add(b2, new GBC(2, r).setAnchor(GBC.WEST));
+ group.add(b2);
+ b2.addActionListener(event ->
+ {
+ hints.put(k, v2);
+ canvas.setRenderingHints(hints);
+ });
+ hints.put(k, v1);
+ r++;
+ }
+ catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+}
+
+/**
+ * This component produces a drawing that shows the effect of rendering hints.
+ */
+class RenderQualityComponent extends JComponent
+{
+ private static final Dimension PREFERRED_SIZE = new Dimension(750, 150);
+ private RenderingHints hints = new RenderingHints(null);
+ private Image image;
+
+ public RenderQualityComponent()
+ {
+ image = new ImageIcon(getClass().getResource("face.gif")).getImage();
+ }
+
+ public void paintComponent(Graphics g)
+ {
+ Graphics2D g2 = (Graphics2D) g;
+ g2.setRenderingHints(hints);
+
+ g2.draw(new Ellipse2D.Double(10, 10, 60, 50));
+ g2.setFont(new Font("Serif", Font.ITALIC, 40));
+ g2.drawString("Hello", 75, 50);
+
+ g2.draw(new Rectangle2D.Double(200, 10, 40, 40));
+ g2.draw(new Line2D.Double(201, 11, 239, 49));
+
+ g2.drawImage(image, 250, 10, 100, 100, null);
+ }
+
+ /**
+ * Sets the hints and repaints.
+ * @param h the rendering hints
+ */
+ public void setRenderingHints(RenderingHints h)
+ {
+ hints = h;
+ repaint();
+ }
+
+ public Dimension getPreferredSize() { return PREFERRED_SIZE; }
+}
diff --git a/corejava第10版/v2ch11/renderQuality/face.gif b/corejava第10版/v2ch11/renderQuality/face.gif
new file mode 100644
index 0000000..7fbdbaa
Binary files /dev/null and b/corejava第10版/v2ch11/renderQuality/face.gif differ
diff --git a/corejava第10版/v2ch11/serialTransfer/SerialTransferFrame.java b/corejava第10版/v2ch11/serialTransfer/SerialTransferFrame.java
new file mode 100644
index 0000000..cd819e9
--- /dev/null
+++ b/corejava第10版/v2ch11/serialTransfer/SerialTransferFrame.java
@@ -0,0 +1,117 @@
+package serialTransfer;
+
+import java.awt.*;
+import java.awt.datatransfer.*;
+import java.awt.event.*;
+import java.io.*;
+import javax.swing.*;
+
+/**
+ * This frame contains a color chooser, and copy and paste buttons.
+ */
+class SerialTransferFrame extends JFrame
+{
+ private JColorChooser chooser;
+
+ public SerialTransferFrame()
+ {
+ chooser = new JColorChooser();
+ add(chooser, BorderLayout.CENTER);
+ JPanel panel = new JPanel();
+
+ JButton copyButton = new JButton("Copy");
+ panel.add(copyButton);
+ copyButton.addActionListener(event -> copy());
+
+ JButton pasteButton = new JButton("Paste");
+ panel.add(pasteButton);
+ pasteButton.addActionListener(event -> paste());
+
+ add(panel, BorderLayout.SOUTH);
+ pack();
+ }
+
+ /**
+ * Copies the chooser's color into the system clipboard.
+ */
+ private void copy()
+ {
+ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ Color color = chooser.getColor();
+ SerialTransferable selection = new SerialTransferable(color);
+ clipboard.setContents(selection, null);
+ }
+
+ /**
+ * Pastes the color from the system clipboard into the chooser.
+ */
+ private void paste()
+ {
+ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ try
+ {
+ DataFlavor flavor = new DataFlavor(
+ "application/x-java-serialized-object;class=java.awt.Color");
+ if (clipboard.isDataFlavorAvailable(flavor))
+ {
+ Color color = (Color) clipboard.getData(flavor);
+ chooser.setColor(color);
+ }
+ }
+ catch (ClassNotFoundException | UnsupportedFlavorException | IOException ex)
+ {
+ JOptionPane.showMessageDialog(this, ex);
+ }
+ }
+}
+
+/**
+ * This class is a wrapper for the data transfer of serialized objects.
+ */
+class SerialTransferable implements Transferable
+{
+ private Serializable obj;
+
+ /**
+ * Constructs the selection.
+ * @param o any serializable object
+ */
+ SerialTransferable(Serializable o)
+ {
+ obj = o;
+ }
+
+ public DataFlavor[] getTransferDataFlavors()
+ {
+ DataFlavor[] flavors = new DataFlavor[2];
+ Class> type = obj.getClass();
+ String mimeType = "application/x-java-serialized-object;class=" + type.getName();
+ try
+ {
+ flavors[0] = new DataFlavor(mimeType);
+ flavors[1] = DataFlavor.stringFlavor;
+ return flavors;
+ }
+ catch (ClassNotFoundException e)
+ {
+ return new DataFlavor[0];
+ }
+ }
+
+ public boolean isDataFlavorSupported(DataFlavor flavor)
+ {
+ return DataFlavor.stringFlavor.equals(flavor)
+ || "application".equals(flavor.getPrimaryType())
+ && "x-java-serialized-object".equals(flavor.getSubType())
+ && flavor.getRepresentationClass().isAssignableFrom(obj.getClass());
+ }
+
+ public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException
+ {
+ if (!isDataFlavorSupported(flavor)) throw new UnsupportedFlavorException(flavor);
+
+ if (DataFlavor.stringFlavor.equals(flavor)) return obj.toString();
+
+ return obj;
+ }
+}
diff --git a/corejava第10版/v2ch11/serialTransfer/SerialTransferTest.java b/corejava第10版/v2ch11/serialTransfer/SerialTransferTest.java
new file mode 100644
index 0000000..886ed0c
--- /dev/null
+++ b/corejava第10版/v2ch11/serialTransfer/SerialTransferTest.java
@@ -0,0 +1,23 @@
+package serialTransfer;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates the transfer of serialized objects between virtual machines.
+ * @version 1.03 2016-05-10
+ * @author Cay Horstmann
+ */
+public class SerialTransferTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new SerialTransferFrame();
+ frame.setTitle("SerialTransferTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch11/shape/ShapeTest.java b/corejava第10版/v2ch11/shape/ShapeTest.java
new file mode 100644
index 0000000..dbab2e6
--- /dev/null
+++ b/corejava第10版/v2ch11/shape/ShapeTest.java
@@ -0,0 +1,346 @@
+package shape;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import java.util.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates the various 2D shapes.
+ * @version 1.03 2016-05-10
+ * @author Cay Horstmann
+ */
+public class ShapeTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new ShapeTestFrame();
+ frame.setTitle("ShapeTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * This frame contains a combo box to select a shape and a component to draw it.
+ */
+class ShapeTestFrame extends JFrame
+{
+ public ShapeTestFrame()
+ {
+ final ShapeComponent comp = new ShapeComponent();
+ add(comp, BorderLayout.CENTER);
+ final JComboBox comboBox = new JComboBox<>();
+ comboBox.addItem(new LineMaker());
+ comboBox.addItem(new RectangleMaker());
+ comboBox.addItem(new RoundRectangleMaker());
+ comboBox.addItem(new EllipseMaker());
+ comboBox.addItem(new ArcMaker());
+ comboBox.addItem(new PolygonMaker());
+ comboBox.addItem(new QuadCurveMaker());
+ comboBox.addItem(new CubicCurveMaker());
+ comboBox.addActionListener(event ->
+ {
+ ShapeMaker shapeMaker = comboBox.getItemAt(comboBox.getSelectedIndex());
+ comp.setShapeMaker(shapeMaker);
+ });
+ add(comboBox, BorderLayout.NORTH);
+ comp.setShapeMaker((ShapeMaker) comboBox.getItemAt(0));
+ pack();
+ }
+}
+
+/**
+ * This component draws a shape and allows the user to move the points that define it.
+ */
+class ShapeComponent extends JComponent
+{
+ private static final Dimension PREFERRED_SIZE = new Dimension(300, 200);
+ private Point2D[] points;
+ private static Random generator = new Random();
+ private static int SIZE = 10;
+ private int current;
+ private ShapeMaker shapeMaker;
+
+ public ShapeComponent()
+ {
+ addMouseListener(new MouseAdapter()
+ {
+ public void mousePressed(MouseEvent event)
+ {
+ Point p = event.getPoint();
+ for (int i = 0; i < points.length; i++)
+ {
+ double x = points[i].getX() - SIZE / 2;
+ double y = points[i].getY() - SIZE / 2;
+ Rectangle2D r = new Rectangle2D.Double(x, y, SIZE, SIZE);
+ if (r.contains(p))
+ {
+ current = i;
+ return;
+ }
+ }
+ }
+
+ public void mouseReleased(MouseEvent event)
+ {
+ current = -1;
+ }
+ });
+ addMouseMotionListener(new MouseMotionAdapter()
+ {
+ public void mouseDragged(MouseEvent event)
+ {
+ if (current == -1) return;
+ points[current] = event.getPoint();
+ repaint();
+ }
+ });
+ current = -1;
+ }
+
+ /**
+ * Set a shape maker and initialize it with a random point set.
+ * @param aShapeMaker a shape maker that defines a shape from a point set
+ */
+ public void setShapeMaker(ShapeMaker aShapeMaker)
+ {
+ shapeMaker = aShapeMaker;
+ int n = shapeMaker.getPointCount();
+ points = new Point2D[n];
+ for (int i = 0; i < n; i++)
+ {
+ double x = generator.nextDouble() * getWidth();
+ double y = generator.nextDouble() * getHeight();
+ points[i] = new Point2D.Double(x, y);
+ }
+ repaint();
+ }
+
+ public void paintComponent(Graphics g)
+ {
+ if (points == null) return;
+ Graphics2D g2 = (Graphics2D) g;
+ for (int i = 0; i < points.length; i++)
+ {
+ double x = points[i].getX() - SIZE / 2;
+ double y = points[i].getY() - SIZE / 2;
+ g2.fill(new Rectangle2D.Double(x, y, SIZE, SIZE));
+ }
+
+ g2.draw(shapeMaker.makeShape(points));
+ }
+
+ public Dimension getPreferredSize() { return PREFERRED_SIZE; }
+}
+
+/**
+ * A shape maker can make a shape from a point set. Concrete subclasses must return a shape in the
+ * makeShape method.
+ */
+abstract class ShapeMaker
+{
+ private int pointCount;
+
+ /**
+ * Constructs a shape maker.
+ * @param ointCount the number of points needed to define this shape.
+ */
+ public ShapeMaker(int pointCount)
+ {
+ this.pointCount = pointCount;
+ }
+
+ /**
+ * Gets the number of points needed to define this shape.
+ * @return the point count
+ */
+ public int getPointCount()
+ {
+ return pointCount;
+ }
+
+ /**
+ * Makes a shape out of the given point set.
+ * @param p the points that define the shape
+ * @return the shape defined by the points
+ */
+ public abstract Shape makeShape(Point2D[] p);
+
+ public String toString()
+ {
+ return getClass().getName();
+ }
+}
+
+/**
+ * Makes a line that joins two given points.
+ */
+class LineMaker extends ShapeMaker
+{
+ public LineMaker()
+ {
+ super(2);
+ }
+
+ public Shape makeShape(Point2D[] p)
+ {
+ return new Line2D.Double(p[0], p[1]);
+ }
+}
+
+/**
+ * Makes a rectangle that joins two given corner points.
+ */
+class RectangleMaker extends ShapeMaker
+{
+ public RectangleMaker()
+ {
+ super(2);
+ }
+
+ public Shape makeShape(Point2D[] p)
+ {
+ Rectangle2D s = new Rectangle2D.Double();
+ s.setFrameFromDiagonal(p[0], p[1]);
+ return s;
+ }
+}
+
+/**
+ * Makes a round rectangle that joins two given corner points.
+ */
+class RoundRectangleMaker extends ShapeMaker
+{
+ public RoundRectangleMaker()
+ {
+ super(2);
+ }
+
+ public Shape makeShape(Point2D[] p)
+ {
+ RoundRectangle2D s = new RoundRectangle2D.Double(0, 0, 0, 0, 20, 20);
+ s.setFrameFromDiagonal(p[0], p[1]);
+ return s;
+ }
+}
+
+/**
+ * Makes an ellipse contained in a bounding box with two given corner points.
+ */
+class EllipseMaker extends ShapeMaker
+{
+ public EllipseMaker()
+ {
+ super(2);
+ }
+
+ public Shape makeShape(Point2D[] p)
+ {
+ Ellipse2D s = new Ellipse2D.Double();
+ s.setFrameFromDiagonal(p[0], p[1]);
+ return s;
+ }
+}
+
+/**
+ * Makes an arc contained in a bounding box with two given corner points, and with starting and
+ * ending angles given by lines emanating from the center of the bounding box and ending in two
+ * given points. To show the correctness of the angle computation, the returned shape contains the
+ * arc, the bounding box, and the lines.
+ */
+class ArcMaker extends ShapeMaker
+{
+ public ArcMaker()
+ {
+ super(4);
+ }
+
+ public Shape makeShape(Point2D[] p)
+ {
+ double centerX = (p[0].getX() + p[1].getX()) / 2;
+ double centerY = (p[0].getY() + p[1].getY()) / 2;
+ double width = Math.abs(p[1].getX() - p[0].getX());
+ double height = Math.abs(p[1].getY() - p[0].getY());
+
+ double skewedStartAngle = Math.toDegrees(Math.atan2(-(p[2].getY() - centerY) * width,
+ (p[2].getX() - centerX) * height));
+ double skewedEndAngle = Math.toDegrees(Math.atan2(-(p[3].getY() - centerY) * width,
+ (p[3].getX() - centerX) * height));
+ double skewedAngleDifference = skewedEndAngle - skewedStartAngle;
+ if (skewedStartAngle < 0) skewedStartAngle += 360;
+ if (skewedAngleDifference < 0) skewedAngleDifference += 360;
+
+ Arc2D s = new Arc2D.Double(0, 0, 0, 0, skewedStartAngle, skewedAngleDifference, Arc2D.OPEN);
+ s.setFrameFromDiagonal(p[0], p[1]);
+
+ GeneralPath g = new GeneralPath();
+ g.append(s, false);
+ Rectangle2D r = new Rectangle2D.Double();
+ r.setFrameFromDiagonal(p[0], p[1]);
+ g.append(r, false);
+ Point2D center = new Point2D.Double(centerX, centerY);
+ g.append(new Line2D.Double(center, p[2]), false);
+ g.append(new Line2D.Double(center, p[3]), false);
+ return g;
+ }
+}
+
+/**
+ * Makes a polygon defined by six corner points.
+ */
+class PolygonMaker extends ShapeMaker
+{
+ public PolygonMaker()
+ {
+ super(6);
+ }
+
+ public Shape makeShape(Point2D[] p)
+ {
+ GeneralPath s = new GeneralPath();
+ s.moveTo((float) p[0].getX(), (float) p[0].getY());
+ for (int i = 1; i < p.length; i++)
+ s.lineTo((float) p[i].getX(), (float) p[i].getY());
+ s.closePath();
+ return s;
+ }
+}
+
+/**
+ * Makes a quad curve defined by two end points and a control point.
+ */
+class QuadCurveMaker extends ShapeMaker
+{
+ public QuadCurveMaker()
+ {
+ super(3);
+ }
+
+ public Shape makeShape(Point2D[] p)
+ {
+ return new QuadCurve2D.Double(p[0].getX(), p[0].getY(), p[1].getX(), p[1].getY(),
+ p[2].getX(), p[2].getY());
+ }
+}
+
+/**
+ * Makes a cubic curve defined by two end points and two control points.
+ */
+class CubicCurveMaker extends ShapeMaker
+{
+ public CubicCurveMaker()
+ {
+ super(4);
+ }
+
+ public Shape makeShape(Point2D[] p)
+ {
+ return new CubicCurve2D.Double(p[0].getX(), p[0].getY(), p[1].getX(), p[1].getY(), p[2]
+ .getX(), p[2].getY(), p[3].getX(), p[3].getY());
+ }
+}
diff --git a/corejava第10版/v2ch11/splashScreen/SplashScreenTest.java b/corejava第10版/v2ch11/splashScreen/SplashScreenTest.java
new file mode 100644
index 0000000..847522f
--- /dev/null
+++ b/corejava第10版/v2ch11/splashScreen/SplashScreenTest.java
@@ -0,0 +1,131 @@
+package splashScreen;
+
+import java.awt.*;
+import java.util.List;
+import javax.swing.*;
+
+/**
+ * This program demonstrates the splash screen API.
+ * @version 1.01 2016-05-10
+ * @author Cay Horstmann
+ */
+public class SplashScreenTest
+{
+ private static final int DEFAULT_WIDTH = 300;
+ private static final int DEFAULT_HEIGHT = 300;
+
+ private static SplashScreen splash;
+
+ private static void drawOnSplash(int percent)
+ {
+ Rectangle bounds = splash.getBounds();
+ Graphics2D g = splash.createGraphics();
+ int height = 20;
+ int x = 2;
+ int y = bounds.height - height - 2;
+ int width = bounds.width - 4;
+ Color brightPurple = new Color(76, 36, 121);
+ g.setColor(brightPurple);
+ g.fillRect(x, y, width * percent / 100, height);
+ splash.update();
+ }
+
+ /**
+ * This method draws on the splash screen.
+ */
+ private static void init1()
+ {
+ splash = SplashScreen.getSplashScreen();
+ if (splash == null)
+ {
+ System.err.println("Did you specify a splash image with -splash or in the manifest?");
+ System.exit(1);
+ }
+
+ try
+ {
+ for (int i = 0; i <= 100; i++)
+ {
+ drawOnSplash(i);
+ Thread.sleep(100); // simulate startup work
+ }
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+
+ /**
+ * This method displays a frame with the same image as the splash screen.
+ */
+ private static void init2()
+ {
+ final Image img = new ImageIcon(splash.getImageURL()).getImage();
+
+ final JFrame splashFrame = new JFrame();
+ splashFrame.setUndecorated(true);
+
+ final JPanel splashPanel = new JPanel()
+ {
+ public void paintComponent(Graphics g)
+ {
+ g.drawImage(img, 0, 0, null);
+ }
+ };
+
+ final JProgressBar progressBar = new JProgressBar();
+ progressBar.setStringPainted(true);
+ splashPanel.setLayout(new BorderLayout());
+ splashPanel.add(progressBar, BorderLayout.SOUTH);
+
+ splashFrame.add(splashPanel);
+ splashFrame.setBounds(splash.getBounds());
+ splashFrame.setVisible(true);
+
+ new SwingWorker()
+ {
+ protected Void doInBackground() throws Exception
+ {
+ try
+ {
+ for (int i = 0; i <= 100; i++)
+ {
+ publish(i);
+ Thread.sleep(100);
+ }
+ }
+ catch (InterruptedException e)
+ {
+ }
+ return null;
+ }
+
+ protected void process(List chunks)
+ {
+ for (Integer chunk : chunks)
+ {
+ progressBar.setString("Loading module " + chunk);
+ progressBar.setValue(chunk);
+ splashPanel.repaint(); // because img is loaded asynchronously
+ }
+ }
+
+ protected void done()
+ {
+ splashFrame.setVisible(false);
+
+ JFrame frame = new JFrame();
+ frame.setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setTitle("SplashScreenTest");
+ frame.setVisible(true);
+ }
+ }.execute();
+ }
+
+ public static void main(String args[])
+ {
+ init1();
+ EventQueue.invokeLater(() -> init2());
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch11/splashScreen/splash.png b/corejava第10版/v2ch11/splashScreen/splash.png
new file mode 100644
index 0000000..19643b3
Binary files /dev/null and b/corejava第10版/v2ch11/splashScreen/splash.png differ
diff --git a/corejava第10版/v2ch11/stroke/StrokeTest.java b/corejava第10版/v2ch11/stroke/StrokeTest.java
new file mode 100644
index 0000000..da259ba
--- /dev/null
+++ b/corejava第10版/v2ch11/stroke/StrokeTest.java
@@ -0,0 +1,221 @@
+package stroke;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.awt.geom.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates different stroke types.
+ * @version 1.04 2016-05-10
+ * @author Cay Horstmann
+ */
+public class StrokeTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new StrokeTestFrame();
+ frame.setTitle("StrokeTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
+
+/**
+ * This frame lets the user choose the cap, join, and line style, and shows the resulting stroke.
+ */
+class StrokeTestFrame extends JFrame
+{
+ private StrokeComponent canvas;
+ private JPanel buttonPanel;
+
+ public StrokeTestFrame()
+ {
+ canvas = new StrokeComponent();
+ add(canvas, BorderLayout.CENTER);
+
+ buttonPanel = new JPanel();
+ buttonPanel.setLayout(new GridLayout(3, 3));
+ add(buttonPanel, BorderLayout.NORTH);
+
+ ButtonGroup group1 = new ButtonGroup();
+ makeCapButton("Butt Cap", BasicStroke.CAP_BUTT, group1);
+ makeCapButton("Round Cap", BasicStroke.CAP_ROUND, group1);
+ makeCapButton("Square Cap", BasicStroke.CAP_SQUARE, group1);
+
+ ButtonGroup group2 = new ButtonGroup();
+ makeJoinButton("Miter Join", BasicStroke.JOIN_MITER, group2);
+ makeJoinButton("Bevel Join", BasicStroke.JOIN_BEVEL, group2);
+ makeJoinButton("Round Join", BasicStroke.JOIN_ROUND, group2);
+
+ ButtonGroup group3 = new ButtonGroup();
+ makeDashButton("Solid Line", false, group3);
+ makeDashButton("Dashed Line", true, group3);
+ }
+
+ /**
+ * Makes a radio button to change the cap style.
+ * @param label the button label
+ * @param style the cap style
+ * @param group the radio button group
+ */
+ private void makeCapButton(String label, final int style, ButtonGroup group)
+ {
+ // select first button in group
+ boolean selected = group.getButtonCount() == 0;
+ JRadioButton button = new JRadioButton(label, selected);
+ buttonPanel.add(button);
+ group.add(button);
+ button.addActionListener(event -> canvas.setCap(style));
+ pack();
+ }
+
+ /**
+ * Makes a radio button to change the join style.
+ * @param label the button label
+ * @param style the join style
+ * @param group the radio button group
+ */
+ private void makeJoinButton(String label, final int style, ButtonGroup group)
+ {
+ // select first button in group
+ boolean selected = group.getButtonCount() == 0;
+ JRadioButton button = new JRadioButton(label, selected);
+ buttonPanel.add(button);
+ group.add(button);
+ button.addActionListener(event -> canvas.setJoin(style));
+ }
+
+ /**
+ * Makes a radio button to set solid or dashed lines
+ * @param label the button label
+ * @param style false for solid, true for dashed lines
+ * @param group the radio button group
+ */
+ private void makeDashButton(String label, final boolean style, ButtonGroup group)
+ {
+ // select first button in group
+ boolean selected = group.getButtonCount() == 0;
+ JRadioButton button = new JRadioButton(label, selected);
+ buttonPanel.add(button);
+ group.add(button);
+ button.addActionListener(event -> canvas.setDash(style));
+ }
+}
+
+/**
+ * This component draws two joined lines, using different stroke objects, and allows the user to
+ * drag the three points defining the lines.
+ */
+class StrokeComponent extends JComponent
+{
+ private static final Dimension PREFERRED_SIZE = new Dimension(400, 400);
+ private static int SIZE = 10;
+
+ private Point2D[] points;
+ private int current;
+ private float width;
+ private int cap;
+ private int join;
+ private boolean dash;
+
+ public StrokeComponent()
+ {
+ addMouseListener(new MouseAdapter()
+ {
+ public void mousePressed(MouseEvent event)
+ {
+ Point p = event.getPoint();
+ for (int i = 0; i < points.length; i++)
+ {
+ double x = points[i].getX() - SIZE / 2;
+ double y = points[i].getY() - SIZE / 2;
+ Rectangle2D r = new Rectangle2D.Double(x, y, SIZE, SIZE);
+ if (r.contains(p))
+ {
+ current = i;
+ return;
+ }
+ }
+ }
+
+ public void mouseReleased(MouseEvent event)
+ {
+ current = -1;
+ }
+ });
+
+ addMouseMotionListener(new MouseMotionAdapter()
+ {
+ public void mouseDragged(MouseEvent event)
+ {
+ if (current == -1) return;
+ points[current] = event.getPoint();
+ repaint();
+ }
+ });
+
+ points = new Point2D[3];
+ points[0] = new Point2D.Double(200, 100);
+ points[1] = new Point2D.Double(100, 200);
+ points[2] = new Point2D.Double(200, 200);
+ current = -1;
+ width = 8.0F;
+ }
+
+ public void paintComponent(Graphics g)
+ {
+ Graphics2D g2 = (Graphics2D) g;
+ GeneralPath path = new GeneralPath();
+ path.moveTo((float) points[0].getX(), (float) points[0].getY());
+ for (int i = 1; i < points.length; i++)
+ path.lineTo((float) points[i].getX(), (float) points[i].getY());
+ BasicStroke stroke;
+ if (dash)
+ {
+ float miterLimit = 10.0F;
+ float[] dashPattern = { 10F, 10F, 10F, 10F, 10F, 10F, 30F, 10F, 30F, 10F, 30F, 10F, 10F,
+ 10F, 10F, 10F, 10F, 30F };
+ float dashPhase = 0;
+ stroke = new BasicStroke(width, cap, join, miterLimit, dashPattern, dashPhase);
+ }
+ else stroke = new BasicStroke(width, cap, join);
+ g2.setStroke(stroke);
+ g2.draw(path);
+ }
+
+ /**
+ * Sets the join style.
+ * @param j the join style
+ */
+ public void setJoin(int j)
+ {
+ join = j;
+ repaint();
+ }
+
+ /**
+ * Sets the cap style.
+ * @param c the cap style
+ */
+ public void setCap(int c)
+ {
+ cap = c;
+ repaint();
+ }
+
+ /**
+ * Sets solid or dashed lines.
+ * @param d false for solid, true for dashed lines
+ */
+ public void setDash(boolean d)
+ {
+ dash = d;
+ repaint();
+ }
+
+ public Dimension getPreferredSize() { return PREFERRED_SIZE; }
+}
diff --git a/corejava第10版/v2ch11/systemTray/SystemTrayTest.java b/corejava第10版/v2ch11/systemTray/SystemTrayTest.java
new file mode 100644
index 0000000..2d2e60b
--- /dev/null
+++ b/corejava第10版/v2ch11/systemTray/SystemTrayTest.java
@@ -0,0 +1,103 @@
+package systemTray;
+
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+import java.util.List;
+
+import javax.swing.*;
+import javax.swing.Timer;
+
+/**
+ * This program demonstrates the system tray API.
+ * @version 1.02 2016-05-10
+ * @author Cay Horstmann
+ */
+public class SystemTrayTest
+{
+ public static void main(String[] args)
+ {
+ SystemTrayApp app = new SystemTrayApp();
+ app.init();
+ }
+}
+
+class SystemTrayApp
+{
+ public void init()
+ {
+ final TrayIcon trayIcon;
+
+ if (!SystemTray.isSupported())
+ {
+ System.err.println("System tray is not supported.");
+ return;
+ }
+
+ SystemTray tray = SystemTray.getSystemTray();
+ Image image = new ImageIcon(getClass().getResource("cookie.png")).getImage();
+
+ PopupMenu popup = new PopupMenu();
+ MenuItem exitItem = new MenuItem("Exit");
+ exitItem.addActionListener(event -> System.exit(0));
+ popup.add(exitItem);
+
+ trayIcon = new TrayIcon(image, "Your Fortune", popup);
+
+ trayIcon.setImageAutoSize(true);
+ trayIcon.addActionListener(event ->
+ {
+ trayIcon.displayMessage("How do I turn this off?",
+ "Right-click on the fortune cookie and select Exit.",
+ TrayIcon.MessageType.INFO);
+ });
+
+ try
+ {
+ tray.add(trayIcon);
+ }
+ catch (AWTException e)
+ {
+ System.err.println("TrayIcon could not be added.");
+ return;
+ }
+
+ final List fortunes = readFortunes();
+ Timer timer = new Timer(10000, event ->
+ {
+ int index = (int) (fortunes.size() * Math.random());
+ trayIcon.displayMessage("Your Fortune", fortunes.get(index),
+ TrayIcon.MessageType.INFO);
+ });
+ timer.start();
+ }
+
+ private List readFortunes()
+ {
+ List fortunes = new ArrayList<>();
+ try (InputStream inStream = getClass().getResourceAsStream("fortunes"))
+ {
+ Scanner in = new Scanner(inStream, "UTF-8");
+ StringBuilder fortune = new StringBuilder();
+ while (in.hasNextLine())
+ {
+ String line = in.nextLine();
+ if (line.equals("%"))
+ {
+ fortunes.add(fortune.toString());
+ fortune = new StringBuilder();
+ }
+ else
+ {
+ fortune.append(line);
+ fortune.append(' ');
+ }
+ }
+ }
+ catch (IOException ex)
+ {
+ ex.printStackTrace();
+ }
+ return fortunes;
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch11/systemTray/cookie.png b/corejava第10版/v2ch11/systemTray/cookie.png
new file mode 100644
index 0000000..1043da5
Binary files /dev/null and b/corejava第10版/v2ch11/systemTray/cookie.png differ
diff --git a/corejava第10版/v2ch11/systemTray/fortunes b/corejava第10版/v2ch11/systemTray/fortunes
new file mode 100644
index 0000000..977703e
--- /dev/null
+++ b/corejava第10版/v2ch11/systemTray/fortunes
@@ -0,0 +1,916 @@
+A day for firm decisions!!!!! Or is it?
+%
+A few hours grace before the madness begins again.
+%
+A gift of a flower will soon be made to you.
+%
+A long-forgotten loved one will appear soon.
+
+Buy the negatives at any price.
+%
+A tall, dark stranger will have more fun than you.
+%
+A visit to a fresh place will bring strange work.
+%
+A visit to a strange place will bring fresh work.
+%
+A vivid and creative mind characterizes you.
+%
+Abandon the search for Truth; settle for a good fantasy.
+%
+Accent on helpful side of your nature. Drain the moat.
+%
+Advancement in position.
+%
+After your lover has gone you will still have PEANUT BUTTER!
+%
+Afternoon very favorable for romance. Try a single person for a change.
+%
+Alimony and bribes will engage a large share of your wealth.
+%
+All the troubles you have will pass away very quickly.
+%
+Among the lucky, you are the chosen one.
+%
+An avocado-tone refrigerator would look good on your resume.
+%
+An exotic journey in downtown Newark is in your future.
+%
+Another good night not to sleep in a eucalyptus tree.
+%
+Are you a turtle?
+%
+Are you ever going to do the dishes? Or will you change your major to biology?
+%
+Are you making all this up as you go along?
+%
+Are you sure the back door is locked?
+%
+Artistic ventures highlighted. Rob a museum.
+%
+Avert misunderstanding by calm, poise, and balance.
+%
+Avoid gunfire in the bathroom tonight.
+%
+Avoid reality at all costs.
+%
+Bank error in your favor. Collect $200.
+%
+Be careful! Is it classified?
+%
+Be careful! UGLY strikes 9 out of 10!
+%
+Be cautious in your daily affairs.
+%
+Be cheerful while you are alive.
+ -- Phathotep, 24th Century B.C.
+%
+Be different: conform.
+%
+Be free and open and breezy! Enjoy! Things won't get any better so
+get used to it.
+%
+Be security conscious -- National defense is at stake.
+%
+Beauty and harmony are as necessary to you as the very breath of life.
+%
+Best of all is never to have been born. Second best is to die soon.
+%
+Better hope the life-inspector doesn't come around while you have your
+life in such a mess.
+%
+Beware of a dark-haired man with a loud tie.
+%
+Beware of a tall black man with one blond shoe.
+%
+Beware of a tall blond man with one black shoe.
+%
+Beware of Bigfoot!
+%
+Beware of low-flying butterflies.
+%
+Beware the one behind you.
+%
+Blow it out your ear.
+%
+Break into jail and claim police brutality.
+%
+Bridge ahead. Pay troll.
+%
+Caution: breathing may be hazardous to your health.
+%
+Caution: Keep out of reach of children.
+%
+Celebrate Hannibal Day this year. Take an elephant to lunch.
+%
+Change your thoughts and you change your world.
+%
+Cheer Up! Things are getting worse at a slower rate.
+%
+Chess tonight.
+%
+Chicken Little only has to be right once.
+%
+Chicken Little was right.
+%
+Cold hands, no gloves.
+%
+Communicate! It can't make things any worse.
+%
+Courage is your greatest present need.
+%
+Day of inquiry. You will be subpoenaed.
+%
+Do not overtax your powers.
+%
+Do not sleep in a eucalyptus tree tonight.
+%
+Do nothing unless you must, and when you must act -- hesitate.
+%
+Do something unusual today. Pay a bill.
+%
+Do what comes naturally. Seethe and fume and throw a tantrum.
+%
+Domestic happiness and faithful friends.
+%
+Don't feed the bats tonight.
+%
+Don't get stuck in a closet -- wear yourself out.
+%
+Don't get to bragging.
+%
+Don't go surfing in South Dakota for a while.
+%
+Don't hate yourself in the morning -- sleep till noon.
+%
+Don't kiss an elephant on the lips today.
+%
+Don't let your mind wander -- it's too little to be let out alone.
+%
+Don't look back, the lemmings are gaining on you.
+%
+Don't look now, but the man in the moon is laughing at you.
+%
+Don't look now, but there is a multi-legged creature on your shoulder.
+%
+Don't plan any hasty moves. You'll be evicted soon anyway.
+%
+Don't read any sky-writing for the next two weeks.
+%
+Don't read everything you believe.
+%
+Don't relax! It's only your tension that's holding you together.
+%
+Don't tell any big lies today. Small ones can be just as effective.
+%
+Don't worry so loud, your roommate can't think.
+%
+Don't Worry, Be Happy.
+ -- Meher Baba
+%
+Don't worry. Life's too long.
+ -- Vincent Sardi, Jr.
+%
+Don't you feel more like you do now than you did when you came in?
+%
+Don't you wish you had more energy... or less ambition?
+%
+Everything that you know is wrong, but you can be straightened out.
+%
+Everything will be just tickety-boo today.
+%
+Excellent day for putting Slinkies on an escalator.
+%
+Excellent day to have a rotten day.
+%
+Excellent time to become a missing person.
+%
+Executive ability is prominent in your make-up.
+%
+Exercise caution in your daily affairs.
+%
+Expect a letter from a friend who will ask a favor of you.
+%
+Expect the worst, it's the least you can do.
+%
+Fine day for friends.
+So-so day for you.
+%
+Fine day to work off excess energy. Steal something heavy.
+%
+Fortune: You will be attacked next Wednesday at 3:15 p.m. by six samurai
+sword wielding purple fish glued to Harley-Davidson motorcycles.
+
+Oh, and have a nice day!
+ -- Bryce Nesbitt '84
+%
+Future looks spotty. You will spill soup in late evening.
+%
+Generosity and perfection are your everlasting goals.
+%
+Give him an evasive answer.
+%
+Give thought to your reputation. Consider changing name and moving to
+a new town.
+%
+Give your very best today. Heaven knows it's little enough.
+%
+Go to a movie tonight. Darkness becomes you.
+%
+Good day for a change of scene. Repaper the bedroom wall.
+%
+Good day for overcoming obstacles. Try a steeplechase.
+%
+Good day to deal with people in high places; particularly lonely stewardesses.
+%
+Good day to let down old friends who need help.
+%
+Good news from afar can bring you a welcome visitor.
+%
+Good news. Ten weeks from Friday will be a pretty good day.
+%
+Good night to spend with family, but avoid arguments with your mate's
+new lover.
+%
+Green light in A.M. for new projects. Red light in P.M. for traffic tickets.
+%
+Hope that the day after you die is a nice day.
+%
+If you can read this, you're too close.
+%
+If you learn one useless thing every day, in a single year you'll learn
+365 useless things.
+%
+If you sow your wild oats, hope for a crop failure.
+%
+If you stand on your head, you will get footprints in your hair.
+%
+If you think last Tuesday was a drag, wait till you see what happens tomorrow!
+%
+If your life was a horse, you'd have to shoot it.
+%
+In the stairway of life, you'd best take the elevator.
+%
+Increased knowledge will help you now. Have mate's phone bugged.
+%
+Is that really YOU that is reading this?
+%
+Is this really happening?
+%
+It is so very hard to be an
+on-your-own-take-care-of-yourself-because-there-is-no-one-else-to-do-it-for-you
+grown-up.
+%
+It may or may not be worthwhile, but it still has to be done.
+%
+It was all so different before everything changed.
+%
+It's a very *__UN*lucky week in which to be took dead.
+ -- Churchy La Femme
+%
+It's all in the mind, ya know.
+%
+It's lucky you're going so slowly, because you're going in the wrong direction.
+%
+Just because the message may never be received does not mean it is
+not worth sending.
+%
+Just to have it is enough.
+%
+Keep emotionally active. Cater to your favorite neurosis.
+%
+Keep it short for pithy sake.
+%
+Lady Luck brings added income today. Lady friend takes it away tonight.
+%
+Learn to pause -- or nothing worthwhile can catch up to you.
+%
+Let me put it this way: today is going to be a learning experience.
+%
+Life is to you a dashing and bold adventure.
+%
+"Life, loathe it or ignore it, you can't like it."
+ -- Marvin, "Hitchhiker's Guide to the Galaxy"
+%
+Live in a world of your own, but always welcome visitors.
+%
+Living your life is a task so difficult, it has never been attempted before.
+%
+Long life is in store for you.
+%
+Look afar and see the end from the beginning.
+%
+Love is in the offing. Be affectionate to one who adores you.
+%
+Make a wish, it might come true.
+%
+Many changes of mind and mood; do not hesitate too long.
+%
+Never be led astray onto the path of virtue.
+%
+Never commit yourself! Let someone else commit you.
+%
+Never give an inch!
+%
+Never look up when dragons fly overhead.
+%
+Never reveal your best argument.
+%
+Next Friday will not be your lucky day. As a matter of fact, you don't
+have a lucky day this year.
+%
+Of course you have a purpose -- to find a purpose.
+%
+People are beginning to notice you. Try dressing before you leave the house.
+%
+Perfect day for scrubbing the floor and other exciting things.
+%
+Questionable day.
+
+Ask somebody something.
+%
+Reply hazy, ask again later.
+%
+Save energy: be apathetic.
+%
+Ships are safe in harbor, but they were never meant to stay there.
+%
+Slow day. Practice crawling.
+%
+Snow Day -- stay home.
+%
+So this is it. We're going to die.
+%
+So you're back... about time...
+%
+Someone is speaking well of you.
+%
+Someone is speaking well of you.
+
+How unusual!
+%
+Someone whom you reject today, will reject you tomorrow.
+%
+Stay away from flying saucers today.
+%
+Stay away from hurricanes for a while.
+%
+Stay the curse.
+%
+That secret you've been guarding, isn't.
+%
+The time is right to make new friends.
+%
+The whole world is a tuxedo and you are a pair of brown shoes.
+ -- George Gobel
+%
+There is a 20% chance of tomorrow.
+%
+There is a fly on your nose.
+%
+There was a phone call for you.
+%
+There will be big changes for you but you will be happy.
+%
+Things will be bright in P.M. A cop will shine a light in your face.
+%
+Think twice before speaking, but don't say "think think click click".
+%
+This life is yours. Some of it was given to you; the rest, you made yourself.
+%
+This will be a memorable month -- no matter how hard you try to forget it.
+%
+Time to be aggressive. Go after a tattooed Virgo.
+%
+Today is National Existential Ennui Awareness Day.
+%
+Today is the first day of the rest of the mess.
+%
+Today is the first day of the rest of your life.
+%
+Today is the last day of your life so far.
+%
+Today is the tomorrow you worried about yesterday.
+%
+Today is what happened to yesterday.
+%
+Today's weirdness is tomorrow's reason why.
+ -- Hunter S. Thompson
+%
+Tomorrow will be cancelled due to lack of interest.
+%
+Tomorrow, this will be part of the unchangeable past but fortunately,
+it can still be changed today.
+%
+Tomorrow, you can be anywhere.
+%
+Tonight you will pay the wages of sin; Don't forget to leave a tip.
+%
+Tonight's the night: Sleep in a eucalyptus tree.
+%
+Troubled day for virgins over 16 who are beautiful and wealthy and live
+in eucalyptus trees.
+%
+Truth will out this morning. (Which may really mess things up.)
+%
+Try the Moo Shu Pork. It is especially good today.
+%
+Try to get all of your posthumous medals in advance.
+%
+Try to have as good a life as you can under the circumstances.
+%
+Try to relax and enjoy the crisis.
+ -- Ashleigh Brilliant
+%
+Try to value useful qualities in one who loves you.
+%
+Tuesday After Lunch is the cosmic time of the week.
+%
+Tuesday is the Wednesday of the rest of your life.
+%
+What happened last night can happen again.
+%
+While you recently had your problems on the run, they've regrouped and
+are making another attack.
+%
+Write yourself a threatening letter and pen a defiant reply.
+%
+You are a bundle of energy, always on the go.
+%
+You are a fluke of the universe; you have no right to be here.
+%
+You are a very redundant person, that's what kind of person you are.
+%
+You are always busy.
+%
+You are as I am with You.
+%
+You are capable of planning your future.
+%
+You are confused; but this is your normal state.
+%
+You are deeply attached to your friends and acquaintances.
+%
+You are destined to become the commandant of the fighting men of the
+department of transportation.
+%
+You are dishonest, but never to the point of hurting a friend.
+%
+You are fairminded, just and loving.
+%
+You are farsighted, a good planner, an ardent lover, and a faithful friend.
+%
+You are fighting for survival in your own sweet and gentle way.
+%
+You are going to have a new love affair.
+%
+You are magnetic in your bearing.
+%
+You are not dead yet. But watch for further reports.
+%
+You are number 6! Who is number one?
+%
+You are only young once, but you can stay immature indefinitely.
+%
+You are scrupulously honest, frank, and straightforward. Therefore you
+have few friends.
+%
+You are sick, twisted and perverted. I like that in a person.
+%
+You are so boring that when I see you my feet go to sleep.
+%
+You are standing on my toes.
+%
+You are taking yourself far too seriously.
+%
+You are the only person to ever get this message.
+%
+You are wise, witty, and wonderful, but you spend too much time reading
+this sort of trash.
+%
+You attempt things that you do not even plan because of your extreme stupidity.
+%
+You can create your own opportunities this week. Blackmail a senior executive.
+%
+You can do very well in speculation where land or anything to do with dirt
+is concerned.
+%
+You can rent this space for only $5 a week.
+%
+You could live a better life, if you had a better mind and a better body.
+%
+You definitely intend to start living sometime soon.
+%
+You dialed 5483.
+%
+You display the wonderful traits of charm and courtesy.
+%
+You don't become a failure until you're satisfied with being one.
+%
+You enjoy the company of other people.
+%
+You feel a whole lot more like you do now than you did when you used to.
+%
+You fill a much-needed gap.
+%
+You get along very well with everyone except animals and people.
+%
+You had some happiness once, but your parents moved away, and you had to
+leave it behind.
+%
+You have a deep appreciation of the arts and music.
+%
+You have a deep interest in all that is artistic.
+%
+You have a reputation for being thoroughly reliable and trustworthy.
+A pity that it's totally undeserved.
+%
+You have a strong appeal for members of the opposite sex.
+%
+You have a strong appeal for members of your own sex.
+%
+You have a strong desire for a home and your family interests come first.
+%
+You have a truly strong individuality.
+%
+You have a will that can be influenced by all with whom you come in contact.
+%
+You have an ability to sense and know higher truth.
+%
+You have an ambitious nature and may make a name for yourself.
+%
+You have an unusual equipment for success. Be sure to use it properly.
+%
+You have an unusual magnetic personality. Don't walk too close to
+metal objects which are not fastened down.
+%
+You have an unusual understanding of the problems of human relationships.
+%
+You have been selected for a secret mission.
+%
+You have Egyptian flu: you're going to be a mummy.
+%
+You have had a long-term stimulation relative to business.
+%
+You have literary talent that you should take pains to develop.
+%
+You have many friends and very few living enemies.
+%
+You have no real enemies.
+%
+You have taken yourself too seriously.
+%
+You have the body of a 19 year old. Please return it before it gets wrinkled.
+%
+You have the capacity to learn from mistakes. You'll learn a lot today.
+%
+You have the power to influence all with whom you come in contact.
+%
+You learn to write as if to someone else because NEXT YEAR YOU WILL BE
+"SOMEONE ELSE."
+%
+You like to form new friendships and make new acquaintances.
+%
+You look like a million dollars. All green and wrinkled.
+%
+You look tired.
+%
+You love peace.
+%
+You love your home and want it to be beautiful.
+%
+You may be gone tomorrow, but that doesn't mean that you weren't here today.
+%
+You may be infinitely smaller than some things, but you're infinitely
+larger than others.
+%
+You may be recognized soon. Hide.
+%
+You may get an opportunity for advancement today. Watch it!
+%
+You may worry about your hair-do today, but tomorrow much peanut butter will
+be sold.
+%
+You need more time; and you probably always will.
+%
+You need no longer worry about the future. This time tomorrow you'll be dead.
+%
+You never hesitate to tackle the most difficult problems.
+%
+You never know how many friends you have until you rent a house on the beach.
+%
+You now have Asian Flu.
+%
+You own a dog, but you can only feed a cat.
+%
+You plan things that you do not even attempt because of your extreme caution.
+%
+You possess a mind not merely twisted, but actually sprained.
+%
+You prefer the company of the opposite sex, but are well liked by your own.
+%
+You recoil from the crude; you tend naturally toward the exquisite.
+%
+You seek to shield those you love and you like the role of the provider.
+%
+You shall be rewarded for a dastardly deed.
+%
+You should emulate your heros, but don't carry it too far. Especially
+if they are dead.
+%
+You should go home.
+%
+You single-handedly fought your way into this hopeless mess.
+%
+You teach best what you most need to learn.
+%
+You too can wear a nose mitten.
+%
+You two ought to be more careful--your love could drag on for years and years.
+%
+You will always get the greatest recognition for the job you least like.
+%
+You will always have good luck in your personal affairs.
+%
+You will attract cultured and artistic people to your home.
+%
+You will be a winner today. Pick a fight with a four-year-old.
+%
+You will be advanced socially, without any special effort on your part.
+%
+You will be aided greatly by a person whom you thought to be unimportant.
+%
+You will be attacked by a beast who has the body of a wolf, the tail of
+a lion, and the face of Donald Duck.
+%
+You will be audited by the Internal Revenue Service.
+%
+You will be awarded a medal for disregarding safety in saving someone.
+%
+You will be awarded some great honor.
+%
+You will be awarded the Nobel Peace Prize... posthumously.
+%
+You will be called upon to help a friend in trouble.
+%
+You will be divorced within a year.
+%
+You will be given a post of trust and responsibility.
+%
+You will be held hostage by a radical group.
+%
+You will be honored for contributing your time and skill to a worthy cause.
+%
+You will be imprisoned for contributing your time and skill to a bank robbery.
+%
+You will be married within a year, and divorced within two.
+%
+You will be married within a year.
+%
+You will be misunderstood by everyone.
+%
+You will be recognized and honored as a community leader.
+%
+You will be reincarnated as a toad; and you will be much happier.
+%
+You will be run over by a beer truck.
+%
+You will be run over by a bus.
+%
+You will be singled out for promotion in your work.
+%
+You will be successful in love.
+%
+You will be surprised by a loud noise.
+%
+You will be surrounded by luxury.
+%
+You will be the last person to buy a Chrysler.
+%
+You will be the victim of a bizarre joke.
+%
+You will be Told about it Tomorrow. Go Home and Prepare Thyself.
+%
+You will be traveling and coming into a fortune.
+%
+You will be winged by an anti-aircraft battery.
+%
+You will become rich and famous unless you don't.
+%
+You will contract a rare disease.
+%
+You will engage in a profitable business activity.
+%
+You will experience a strong urge to do good; but it will pass.
+%
+You will feel hungry again in another hour.
+%
+You will forget that you ever knew me.
+%
+You will gain money by a fattening action.
+%
+You will gain money by a speculation or lottery.
+%
+You will gain money by an illegal action.
+%
+You will gain money by an immoral action.
+%
+You will get what you deserve.
+%
+You will give someone a piece of your mind, which you can ill afford.
+%
+You will have a long and boring life.
+%
+You will have a long and unpleasant discussion with your supervisor.
+%
+You will have domestic happiness and faithful friends.
+%
+You will have good luck and overcome many hardships.
+%
+You will have long and healthy life.
+%
+You will hear good news from one you thought unfriendly to you.
+%
+You will inherit millions of dollars.
+%
+You will inherit some money or a small piece of land.
+%
+You will live a long, healthy, happy life and make bags of money.
+%
+You will live to see your grandchildren.
+%
+You will lose your present job and have to become a door to door mayonnaise
+salesman.
+%
+You will meet an important person who will help you advance professionally.
+%
+You will never know hunger.
+%
+You will not be elected to public office this year.
+%
+You will obey or molten silver will be poured into your ears.
+%
+You will outgrow your usefulness.
+%
+You will overcome the attacks of jealous associates.
+%
+You will pass away very quickly.
+%
+You will pay for your sins. If you have already paid, please disregard
+this message.
+%
+You will pioneer the first Martian colony.
+%
+You will probably marry after a very brief courtship.
+%
+You will reach the highest possible point in your business or profession.
+%
+You will receive a legacy which will place you above want.
+%
+You will remember something that you should not have forgotten.
+%
+You will soon forget this.
+%
+You will soon meet a person who will play an important role in your life.
+%
+You will step on the night soil of many countries.
+%
+You will stop at nothing to reach your objective, but only because your
+brakes are defective.
+%
+You will triumph over your enemy.
+%
+You will visit the Dung Pits of Glive soon.
+%
+You will win success in whatever calling you adopt.
+%
+You will wish you hadn't.
+%
+You work very hard. Don't try to think as well.
+%
+You worry too much about your job. Stop it. You are not paid enough to worry.
+%
+You would if you could but you can't so you won't.
+%
+You'd like to do it instantaneously, but that's too slow.
+%
+You'll be called to a post requiring ability in handling groups of people.
+%
+You'll be sorry...
+%
+You'll feel devilish tonight. Toss dynamite caps under a flamenco dancer's
+heel.
+%
+You'll feel much better once you've given up hope.
+%
+You'll never be the man your mother was!
+%
+You'll never see all the places, or read all the books, but fortunately,
+they're not all recommended.
+%
+You'll wish that you had done some of the hard things when they were easier
+to do.
+%
+You're a card which will have to be dealt with.
+%
+You're almost as happy as you think you are.
+%
+You're at the end of the road again.
+%
+You're being followed. Cut out the hanky-panky for a few days.
+%
+You're currently going through a difficult transition period called "Life."
+%
+You're definitely on their list. The question to ask next is what list it is.
+%
+You're growing out of some of your problems, but there are others that
+you're growing into.
+%
+You're not my type. For that matter, you're not even my species!!!
+%
+You're ugly and your mother dresses you funny.
+%
+You're working under a slight handicap. You happen to be human.
+%
+You've been leading a dog's life. Stay off the furniture.
+%
+Your aim is high and to the right.
+%
+Your aims are high, and you are capable of much.
+%
+Your analyst has you mixed up with another patient. Don't believe a
+thing he tells you.
+%
+Your best consolation is the hope that the things you failed to get weren't
+really worth having.
+%
+Your boss climbed the corporate ladder, wrong by wrong.
+%
+Your boss is a few sandwiches short of a picnic.
+%
+Your boyfriend takes chocolate from strangers.
+%
+Your business will assume vast proportions.
+%
+Your business will go through a period of considerable expansion.
+%
+Your depth of comprehension may tend to make you lax in worldly ways.
+%
+Your domestic life may be harmonious.
+%
+Your fly might be open (but don't check it just now).
+%
+Your goose is cooked.
+(Your current chick is burned up too!)
+%
+Your heart is pure, and your mind clear, and your soul devout.
+%
+Your ignorance cramps my conversation.
+%
+Your life would be very empty if you had nothing to regret.
+%
+Your love life will be happy and harmonious.
+%
+Your love life will be... interesting.
+%
+Your lover will never wish to leave you.
+%
+Your lucky color has faded.
+%
+Your lucky number has been disconnected.
+%
+Your lucky number is 3552664958674928. Watch for it everywhere.
+%
+Your mode of life will be changed for the better because of good news soon.
+%
+Your mode of life will be changed for the better because of new developments.
+%
+Your motives for doing whatever good deed you may have in mind will be
+misinterpreted by somebody.
+%
+Your nature demands love and your happiness depends on it.
+%
+Your object is to save the world, while still leading a pleasant life.
+%
+Your own qualities will help prevent your advancement in the world.
+%
+Your present plans will be successful.
+%
+Your reasoning is excellent -- it's only your basic assumptions that are wrong.
+%
+Your reasoning powers are good, and you are a fairly good planner.
+%
+Your sister swims out to meet troop ships.
+%
+Your society will be sought by people of taste and refinement.
+%
+Your step will soil many countries.
+%
+Your supervisor is thinking about you.
+%
+Your talents will be recognized and suitably rewarded.
+%
+Your temporary financial embarrassment will be relieved in a surprising manner.
+%
+Your true value depends entirely on what you are compared with.
+%
diff --git a/corejava第10版/v2ch11/transferText/TextTransferFrame.java b/corejava第10版/v2ch11/transferText/TextTransferFrame.java
new file mode 100644
index 0000000..92044fc
--- /dev/null
+++ b/corejava第10版/v2ch11/transferText/TextTransferFrame.java
@@ -0,0 +1,68 @@
+package transferText;
+
+import java.awt.*;
+import java.awt.datatransfer.*;
+import java.awt.event.*;
+import java.io.*;
+import javax.swing.*;
+
+/**
+ * This frame has a text area and buttons for copying and pasting text.
+ */
+public class TextTransferFrame extends JFrame
+{
+ private JTextArea textArea;
+ private static final int TEXT_ROWS = 20;
+ private static final int TEXT_COLUMNS = 60;
+
+ public TextTransferFrame()
+ {
+ textArea = new JTextArea(TEXT_ROWS, TEXT_COLUMNS);
+ add(new JScrollPane(textArea), BorderLayout.CENTER);
+ JPanel panel = new JPanel();
+
+ JButton copyButton = new JButton("Copy");
+ panel.add(copyButton);
+ copyButton.addActionListener(event -> copy());
+
+ JButton pasteButton = new JButton("Paste");
+ panel.add(pasteButton);
+ pasteButton.addActionListener(event -> paste());
+
+ add(panel, BorderLayout.SOUTH);
+ pack();
+ }
+
+ /**
+ * Copies the selected text to the system clipboard.
+ */
+ private void copy()
+ {
+ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ String text = textArea.getSelectedText();
+ if (text == null) text = textArea.getText();
+ StringSelection selection = new StringSelection(text);
+ clipboard.setContents(selection, null);
+ }
+
+ /**
+ * Pastes the text from the system clipboard into the text area.
+ */
+ private void paste()
+ {
+ Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
+ DataFlavor flavor = DataFlavor.stringFlavor;
+ if (clipboard.isDataFlavorAvailable(flavor))
+ {
+ try
+ {
+ String text = (String) clipboard.getData(flavor);
+ textArea.replaceSelection(text);
+ }
+ catch (UnsupportedFlavorException e | IOException ex)
+ {
+ JOptionPane.showMessageDialog(this, ex);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch11/transferText/TextTransferTest.java b/corejava第10版/v2ch11/transferText/TextTransferTest.java
new file mode 100644
index 0000000..fec6dd1
--- /dev/null
+++ b/corejava第10版/v2ch11/transferText/TextTransferTest.java
@@ -0,0 +1,24 @@
+package transferText;
+
+import java.awt.*;
+import javax.swing.*;
+
+/**
+ * This program demonstrates the transfer of text between a Java application and the system
+ * clipboard.
+ * @version 1.14 2016-05-10
+ * @author Cay Horstmann
+ */
+public class TextTransferTest
+{
+ public static void main(String[] args)
+ {
+ EventQueue.invokeLater(() ->
+ {
+ JFrame frame = new TextTransferFrame();
+ frame.setTitle("TextTransferTest");
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setVisible(true);
+ });
+ }
+}
\ No newline at end of file
diff --git a/corejava第10版/v2ch12/employee/Employee.c b/corejava第10版/v2ch12/employee/Employee.c
new file mode 100644
index 0000000..eb39bf6
--- /dev/null
+++ b/corejava第10版/v2ch12/employee/Employee.c
@@ -0,0 +1,26 @@
+/**
+ @version 1.10 1999-11-13
+ @author Cay Horstmann
+*/
+
+#include "Employee.h"
+
+#include
+
+JNIEXPORT void JNICALL Java_Employee_raiseSalary(JNIEnv* env, jobject this_obj, jdouble byPercent)
+{
+ /* get the class */
+ jclass class_Employee = (*env)->GetObjectClass(env, this_obj);
+
+ /* get the field ID */
+ jfieldID id_salary = (*env)->GetFieldID(env, class_Employee, "salary", "D");
+
+ /* get the field value */
+ jdouble salary = (*env)->GetDoubleField(env, this_obj, id_salary);
+
+ salary *= 1 + byPercent / 100;
+
+ /* set the field value */
+ (*env)->SetDoubleField(env, this_obj, id_salary, salary);
+}
+
diff --git a/javacore第11版/corejava/v2ch12/employee/Employee.java b/corejava第10版/v2ch12/employee/Employee.java
similarity index 100%
rename from javacore第11版/corejava/v2ch12/employee/Employee.java
rename to corejava第10版/v2ch12/employee/Employee.java
diff --git a/corejava第10版/v2ch12/employee/EmployeeTest.java b/corejava第10版/v2ch12/employee/EmployeeTest.java
new file mode 100644
index 0000000..58b1570
--- /dev/null
+++ b/corejava第10版/v2ch12/employee/EmployeeTest.java
@@ -0,0 +1,21 @@
+/**
+ * @version 1.10 1999-11-13
+ * @author Cay Horstmann
+ */
+
+public class EmployeeTest
+{
+ 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);
+
+ for (Employee e : staff)
+ e.raiseSalary(5);
+ for (Employee e : staff)
+ e.print();
+ }
+}
diff --git a/javacore第11版/corejava/v2ch12/helloNative/HelloNative.c b/corejava第10版/v2ch12/helloNative/HelloNative.c
similarity index 100%
rename from javacore第11版/corejava/v2ch12/helloNative/HelloNative.c
rename to corejava第10版/v2ch12/helloNative/HelloNative.c
diff --git a/javacore第11版/corejava/v2ch12/helloNative/HelloNative.h b/corejava第10版/v2ch12/helloNative/HelloNative.h
similarity index 100%
rename from javacore第11版/corejava/v2ch12/helloNative/HelloNative.h
rename to corejava第10版/v2ch12/helloNative/HelloNative.h
diff --git a/javacore第11版/corejava/v2ch12/helloNative/HelloNative.java b/corejava第10版/v2ch12/helloNative/HelloNative.java
similarity index 100%
rename from javacore第11版/corejava/v2ch12/helloNative/HelloNative.java
rename to corejava第10版/v2ch12/helloNative/HelloNative.java
diff --git a/javacore第11版/corejava/v2ch12/helloNative/HelloNativeTest.java b/corejava第10版/v2ch12/helloNative/HelloNativeTest.java
similarity index 100%
rename from javacore第11版/corejava/v2ch12/helloNative/HelloNativeTest.java
rename to corejava第10版/v2ch12/helloNative/HelloNativeTest.java
diff --git a/corejava第10版/v2ch12/invocation/InvocationTest.c b/corejava第10版/v2ch12/invocation/InvocationTest.c
new file mode 100644
index 0000000..95c8ae5
--- /dev/null
+++ b/corejava第10版/v2ch12/invocation/InvocationTest.c
@@ -0,0 +1,150 @@
+/**
+ @version 1.20 2007-10-26
+ @author Cay Horstmann
+*/
+
+#include
+#include
+
+#ifdef _WINDOWS
+
+#include
+static HINSTANCE loadJVMLibrary(void);
+typedef jint (JNICALL *CreateJavaVM_t)(JavaVM **, void **, JavaVMInitArgs *);
+
+#endif
+
+int main()
+{
+ JavaVMOption options[2];
+ JavaVMInitArgs vm_args;
+ JavaVM *jvm;
+ JNIEnv *env;
+ long status;
+
+ jclass class_Welcome;
+ jclass class_String;
+ jobjectArray args;
+ jmethodID id_main;
+
+#ifdef _WINDOWS
+ HINSTANCE hjvmlib;
+ CreateJavaVM_t createJavaVM;
+#endif
+
+ options[0].optionString = "-Djava.class.path=.";
+
+ memset(&vm_args, 0, sizeof(vm_args));
+ vm_args.version = JNI_VERSION_1_2;
+ vm_args.nOptions = 1;
+ vm_args.options = options;
+
+
+#ifdef _WINDOWS
+ hjvmlib = loadJVMLibrary();
+ createJavaVM = (CreateJavaVM_t) GetProcAddress(hjvmlib, "JNI_CreateJavaVM");
+ status = (*createJavaVM)(&jvm, (void **) &env, &vm_args);
+#else
+ status = JNI_CreateJavaVM(&jvm, (void **) &env, &vm_args);
+#endif
+
+ if (status == JNI_ERR)
+ {
+ fprintf(stderr, "Error creating VM\n");
+ return 1;
+ }
+
+ class_Welcome = (*env)->FindClass(env, "Welcome");
+ id_main = (*env)->GetStaticMethodID(env, class_Welcome, "main", "([Ljava/lang/String;)V");
+
+ class_String = (*env)->FindClass(env, "java/lang/String");
+ args = (*env)->NewObjectArray(env, 0, class_String, NULL);
+ (*env)->CallStaticVoidMethod(env, class_Welcome, id_main, args);
+
+ (*jvm)->DestroyJavaVM(jvm);
+
+ return 0;
+}
+
+#ifdef _WINDOWS
+
+static int GetStringFromRegistry(HKEY key, const char *name, char *buf, jint bufsize)
+{
+ DWORD type, size;
+
+ return RegQueryValueEx(key, name, 0, &type, 0, &size) == 0
+ && type == REG_SZ
+ && size < (unsigned int) bufsize
+ && RegQueryValueEx(key, name, 0, 0, buf, &size) == 0;
+}
+
+static void GetPublicJREHome(char *buf, jint bufsize)
+{
+ HKEY key, subkey;
+ char version[MAX_PATH];
+
+ /* Find the current version of the JRE */
+ char *JRE_KEY = "Software\\JavaSoft\\Java Runtime Environment";
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, JRE_KEY, 0, KEY_READ, &key) != 0)
+ {
+ fprintf(stderr, "Error opening registry key '%s'\n", JRE_KEY);
+ exit(1);
+ }
+
+ if (!GetStringFromRegistry(key, "CurrentVersion", version, sizeof(version)))
+ {
+ fprintf(stderr, "Failed reading value of registry key:\n\t%s\\CurrentVersion\n", JRE_KEY);
+ RegCloseKey(key);
+ exit(1);
+ }
+
+ /* Find directory where the current version is installed. */
+ if (RegOpenKeyEx(key, version, 0, KEY_READ, &subkey) != 0)
+ {
+ fprintf(stderr, "Error opening registry key '%s\\%s'\n", JRE_KEY, version);
+ RegCloseKey(key);
+ exit(1);
+ }
+
+ if (!GetStringFromRegistry(subkey, "JavaHome", buf, bufsize))
+ {
+ fprintf(stderr, "Failed reading value of registry key:\n\t%s\\%s\\JavaHome\n",
+ JRE_KEY, version);
+ RegCloseKey(key);
+ RegCloseKey(subkey);
+ exit(1);
+ }
+
+ RegCloseKey(key);
+ RegCloseKey(subkey);
+}
+
+static HINSTANCE loadJVMLibrary(void)
+{
+ HINSTANCE h1, h2;
+ char msvcdll[MAX_PATH];
+ char javadll[MAX_PATH];
+ GetPublicJREHome(msvcdll, MAX_PATH);
+ strcpy(javadll, msvcdll);
+ strncat(msvcdll, "\\bin\\msvcr71.dll", MAX_PATH - strlen(msvcdll));
+ msvcdll[MAX_PATH - 1] = '\0';
+ strncat(javadll, "\\bin\\client\\jvm.dll", MAX_PATH - strlen(javadll));
+ javadll[MAX_PATH - 1] = '\0';
+
+ h1 = LoadLibrary(msvcdll);
+ if (h1 == NULL)
+ {
+ fprintf(stderr, "Can't load library msvcr71.dll\n");
+ exit(1);
+ }
+
+ h2 = LoadLibrary(javadll);
+ if (h2 == NULL)
+ {
+ fprintf(stderr, "Can't load library jvm.dll\n");
+ exit(1);
+ }
+ return h2;
+}
+
+#endif
diff --git a/corejava第10版/v2ch12/invocation/Welcome.java b/corejava第10版/v2ch12/invocation/Welcome.java
new file mode 100644
index 0000000..909e041
--- /dev/null
+++ b/corejava第10版/v2ch12/invocation/Welcome.java
@@ -0,0 +1,17 @@
+/**
+ * @version 1.20 2004-02-28
+ * @author Cay Horstmann
+ */
+public class Welcome
+{
+ public static void main(String[] args)
+ {
+ String[] greeting = new String[3];
+ greeting[0] = "Welcome to Core Java";
+ greeting[1] = "by Cay Horstmann";
+ greeting[2] = "and Gary Cornell";
+
+ for (String g : greeting)
+ System.out.println(g);
+ }
+}
diff --git a/corejava第10版/v2ch12/printf1/Printf1.c b/corejava第10版/v2ch12/printf1/Printf1.c
new file mode 100644
index 0000000..bfdb636
--- /dev/null
+++ b/corejava第10版/v2ch12/printf1/Printf1.c
@@ -0,0 +1,19 @@
+/**
+ @version 1.10 1997-07-01
+ @author Cay Horstmann
+*/
+
+#include "Printf1.h"
+#include