From a6a565c20fadf0e42b5d9531ea84b2c1f8b86675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=B3=E9=98=B3?= <260893248@qq.com> Date: Wed, 26 Jul 2017 09:32:45 +0800 Subject: [PATCH 01/24] fix typo (from "mete" to "meta") MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 如題 --- docs/CH17.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CH17.md b/docs/CH17.md index 9fc53a5..e8b7fc1 100644 --- a/docs/CH17.md +++ b/docs/CH17.md @@ -1,6 +1,6 @@ # 第 17 章 Annotation -J2SE 5.0 中對 metadata 提出的功能是 Annotation,metadata 就是「資料的資料」(Data about data),突然看到這樣的解釋會覺得奇怪,但以表格為例,表格中呈現的就是資料,但有時候還會有額外的資料用來說明表格的作用,從這個角度來看,metedata 就不這麼的奇怪。 +J2SE 5.0 中對 metadata 提出的功能是 Annotation,metadata 就是「資料的資料」(Data about data),突然看到這樣的解釋會覺得奇怪,但以表格為例,表格中呈現的就是資料,但有時候還會有額外的資料用來說明表格的作用,從這個角度來看,metadata 就不這麼的奇怪。 在 J2SE 5.0 中,Annotation 的主要目的介於原始碼與 API 文件說明之間,Annotation 對程式碼作出一些說明與解釋,Class 中可以包含這些解釋,編譯器或其它程式分析工作可以使用 Annotation 來作分析,您可以從 java.lang.Override、java.lang.Deprecated、java.lang.SuppressWarnings 這三個 J2SE 5.0 中標準的 Annotation 型態開始瞭解 Annotation 的作用。 From 1b84686305f35247bed1608c9be5b659d338307d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=B3=E9=98=B3?= <260893248@qq.com> Date: Wed, 26 Jul 2017 09:47:02 +0800 Subject: [PATCH 02/24] Missing a '.' in the filename MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 如題 --- docs/CH17.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CH17.md b/docs/CH17.md index 9fc53a5..5aebc65 100644 --- a/docs/CH17.md +++ b/docs/CH17.md @@ -69,7 +69,7 @@ java.lang.Deprecated 是 J2SE 5.0 中標準的 Annotation 型態之一,它對 舉個例子來說,您可能定義一個 Something 類別,並在當中定義有 getSomething() 方法,而在這個類別被實際使用一段時間之後,您不建議開發人員使用 getSomething() 方法了,並想要將這個方法標示為 "deprecated",您可以使用 @Deprecated 在 getSomething() 方法加上標示。 -#### **範例 17.3 Somethingjava** +#### **範例 17.3 Something.java** ```java package onlyfun.caterpillar; From 4232bf97d046e071a575ef90d61f5dc54ab1deac Mon Sep 17 00:00:00 2001 From: Justin Lin Date: Wed, 26 Jul 2017 10:22:09 +0800 Subject: [PATCH 03/24] fixed typo --- docs/CH17.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CH17.md b/docs/CH17.md index 736d487..9adecf2 100644 --- a/docs/CH17.md +++ b/docs/CH17.md @@ -407,7 +407,7 @@ Annotation 標示於方法上的話,就要取得方法的 Method 代表實例 TYPE, // 適用 class, interface, enum FIELD, // 適用 field METHOD, // 適用 method - PARAMETER, // 適用 method 上之 parameter + PARAMETER, // 適用 method 上之 parametar CONSTRUCTOR, // 適用 constructor LOCAL_VARIABLE, // 適用區域變數 ANNOTATION_TYPE, // 適用 annotation 型態 From 0270003736b75eeedd67bf82330a783873ea1c2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=B3=E9=98=B3?= <260893248@qq.com> Date: Mon, 14 Aug 2017 10:08:39 +0800 Subject: [PATCH 04/24] fix typo ("TestedField"->"TestField") MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 如題 --- docs/CH16.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CH16.md b/docs/CH16.md index 0fb27b5..1dfd6ae 100644 --- a/docs/CH16.md +++ b/docs/CH16.md @@ -947,7 +947,7 @@ public class CommandUtilDemo { ### 16.2.3 修改成員值 -儘管直接存取類別的資料成員(Field)是不被鼓勵的,但您仍是可以直接存取公開的(public)資料成員,而您甚至也可以透過反射機制來存取私用資料成員,以一個實例來說明,首先撰寫個 TestedField 類別。 +儘管直接存取類別的資料成員(Field)是不被鼓勵的,但您仍是可以直接存取公開的(public)資料成員,而您甚至也可以透過反射機制來存取私用資料成員,以一個實例來說明,首先撰寫個 TestField 類別。 #### **範例 16.20 TestField.java** ```java From ab5ef7d948ede56ca3548e73b2670eafcc6bed8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=B3=E9=98=B3?= <260893248@qq.com> Date: Fri, 25 Aug 2017 16:50:34 +0800 Subject: [PATCH 05/24] trivial (remove one char '`') MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 如题 --- docs/CH09.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CH09.md b/docs/CH09.md index 99948c3..4baafb7 100644 --- a/docs/CH09.md +++ b/docs/CH09.md @@ -497,7 +497,7 @@ public class ImportStaticDemo { 如果您想要 "import" 類別下所有的靜態成員,也可以使用 '\*' 字元,例如將範例 9.10 中的 "import static" 改為以下也是可行的: - `import static java.util.Arrays.*; + import static java.util.Arrays.*; "import static" 語法可以讓您少打一些字,但是您要注意名稱衝突問題,對於名稱衝突編譯器可能透過以下的幾個方法來解決: From 7721d7a639e6aece31ab185a8de8eb690fa39e9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=B3=E9=98=B3?= <260893248@qq.com> Date: Fri, 25 Aug 2017 17:03:06 +0800 Subject: [PATCH 06/24] file name is wrong MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 如题 --- docs/CH09.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CH09.md b/docs/CH09.md index 99948c3..49ec7c2 100644 --- a/docs/CH09.md +++ b/docs/CH09.md @@ -197,7 +197,7 @@ public class PackageDemo { 在編譯時您使用以下的指令指定編譯過後的類別檔案儲存目錄,'.'表示建立在目前的工作位置: - javac -d . UsePackage.java + javac -d . PackageDemo.java 編譯完成之後,在目前的工作位置中會出現 onlyfun 目錄,而 onlyfun 目錄下會有個 caterpillar 目錄,而 caterpillar 目錄下則有一個 PackageDemo.class 檔案,在編譯完成之後,"package" 的設定會成為類別名稱的一部份,也就是完整的類別名稱是 onlyfun.caterpillar.PackageDemo,所以在執行時要這麼下指令以指定類別名稱: From 48438dc83f5329649df0588be2fa747e8ca6150a Mon Sep 17 00:00:00 2001 From: Chyi-Kwei Yau Date: Mon, 11 Dec 2017 15:48:27 -0500 Subject: [PATCH 07/24] typo fix --- docs/CH16.md | 2 +- docs/CH18.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CH16.md b/docs/CH16.md index 1dfd6ae..4d632b5 100644 --- a/docs/CH16.md +++ b/docs/CH16.md @@ -531,7 +531,7 @@ ExtClassLoader 與 AppClassLoader 在程式啟動後會在虛擬機器中存在 Java 的類別載入器階層架構除了可以達到動態載入類別目的之外,還有著安全上的考量,首先,因為每次尋找類別時都是委託 parent 開始尋找,所以除非有人可以侵入您的電腦,置換掉標準 Java SE API 與您自己安裝的延伸套件,否則是不可能藉由撰寫自己的類別載入器來載入惡意類別,以置換掉標準 Java SE API與您自己安裝的延伸套件。 -由於每次的類別載入是由子 ClassLoader 委託父 ClassLoader 先嘗試載入,但父 lassLoader 看不到子 ClassLoader,所以同一階層的子 ClassLoader 不會被誤用,從而避免了載入錯誤類別的可能性,例如在圖 16.4 中,您想從 YourClassLoader 來載入類別的話,類別載入器階層不會看到 MaliciousClassLoader。 +由於每次的類別載入是由子 ClassLoader 委託父 ClassLoader 先嘗試載入,但父 ClassLoader 看不到子 ClassLoader,所以同一階層的子 ClassLoader 不會被誤用,從而避免了載入錯誤類別的可能性,例如在圖 16.4 中,您想從 YourClassLoader 來載入類別的話,類別載入器階層不會看到 MaliciousClassLoader。 ![類別載入器階層的安全設計](../images/img16-04.png) diff --git a/docs/CH18.md b/docs/CH18.md index 990d0b4..380057d 100644 --- a/docs/CH18.md +++ b/docs/CH18.md @@ -486,7 +486,7 @@ Level.ALL 表示顯示所有的訊息,所以這一次的執行結果可顯示 如果您想要關閉所有的訊息,可以設定為 Level.OFF。 -Logger 的 server()、warning()、info() 等方法,實際上是個便捷的方法,您也可以直接使用 log() 方法並指定等級來執行相同的作用,例如範例 18.10 的執行結果與範例 18.9 是一樣的。 +Logger 的 severe()、warning()、info() 等方法,實際上是個便捷的方法,您也可以直接使用 log() 方法並指定等級來執行相同的作用,例如範例 18.10 的執行結果與範例 18.9 是一樣的。 #### **範例 18.10 LoggingLevelDemo3.java** ```java From 32261c93482fcd2fd5e352c0cc5f37a8f099e7ec Mon Sep 17 00:00:00 2001 From: Justin Lin Date: Fri, 22 Dec 2017 13:57:22 +0800 Subject: [PATCH 08/24] updated readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 73c12e5..07c9a95 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Java SE 6 技術手冊 原始碼範例都改為 UTF-8 編碼了,因此使用 `javac` 編譯時,記得加上 `-encoding UTF-8`。 -新的 Java 文件基於 JDK8 而撰寫,你可以在 [我的網站](https://openhome.cc) 上的 [Java Gossip](https://openhome.cc/Gossip/Java/) 進行閱讀。 +新的 Java 文件基於 JDK9 而撰寫,你可以在 [我的網站](https://openhome.cc) 上的 [Java Gossip](https://openhome.cc/Gossip/Java/) 進行閱讀。 ---------- From e1cecf53e30f29892c12f4ac1340e2ebf17370b0 Mon Sep 17 00:00:00 2001 From: Jeff Chen Date: Tue, 23 Jan 2018 16:13:22 -0800 Subject: [PATCH 09/24] Update CH07.md edit typo --- docs/CH07.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CH07.md b/docs/CH07.md index 58f117b..be61983 100644 --- a/docs/CH07.md +++ b/docs/CH07.md @@ -388,7 +388,7 @@ public class SafeArrayDemo { public Account(String number, double money) { accountNumber = number; // 實際等於this.accountNumber = number; - this.balance = money; // 實際等於this.balance = money; + balance = money; // 實際等於this.balance = money; } this 除了用來參考至呼叫方法的實際物件之外,還有一種可以帶引數的用法,主要是用於呼叫建構方法,而避免直接以建構方法的名稱來呼叫,例如在下面的程式片段中,當使用無參數的建構方法 Ball() 時,它會呼叫有參數的建構方法: From c600aa1f0372dcdd8a754e9972e4ea5b2689c78f Mon Sep 17 00:00:00 2001 From: Jeff Chen Date: Tue, 23 Jan 2018 19:16:11 -0800 Subject: [PATCH 10/24] Update CH06.md fix typo --- docs/CH06.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CH06.md b/docs/CH06.md index 8633b18..e666a58 100644 --- a/docs/CH06.md +++ b/docs/CH06.md @@ -310,7 +310,7 @@ public class AppendStringTest { for(int i = 0; i < 10000; i++) builder.append(i); -使用 StringBuilder 最後若要輸出字串結果,可以呼叫其 toString() 方法,您可以使用 length() 方法得知目前物件中的字元長度,而 capacity() 可傳回該物件目前可容納的字元容量,另外 StringBuilder 還有像是 insert() 方法可以將字元插入指定的位置,如果該位置以後有字元,則將所有的字元往後移;deleteChar() 方法可以刪除指定位置的字元,而 reserve() 方法可以反轉字串,詳細的使用可以查詢看看 java.lang.StringBuilder 的 API 文件說明。 +使用 StringBuilder 最後若要輸出字串結果,可以呼叫其 toString() 方法,您可以使用 length() 方法得知目前物件中的字元長度,而 capacity() 可傳回該物件目前可容納的字元容量,另外 StringBuilder 還有像是 insert() 方法可以將字元插入指定的位置,如果該位置以後有字元,則將所有的字元往後移;deleteChar() 方法可以刪除指定位置的字元,而 reverse() 方法可以反轉字串,詳細的使用可以查詢看看 java.lang.StringBuilder 的 API 文件說明。 StringBuilder 是 J2SE 5.0 才新增的類別,在 J2SE 5.0 之前的版本若有相同的需求,是使用 java.lang.StringBuffer,事實上,StringBuilder 被設計為與 StringBuffer 具有相同的操作介面,在單機非「多執行緒」(Multithread)的情況下使用 StringBuilder 會有較好的效率,因為 StringBuilder 沒有處理「同步」(Synchronized)問題;StringBuffer 則會處理同步問題,如果您的 StringBuilder 會在多執行緒下被操作,則要改用 StringBuffer,讓物件自行管理同步問題,關於多執行緒的觀念,會在第 15 章詳細說明。 From eb5360fe110cc484c79d1c35b55ad453cb857560 Mon Sep 17 00:00:00 2001 From: Jeff Chen Date: Tue, 30 Jan 2018 11:09:02 -0800 Subject: [PATCH 11/24] Update CH08.md fix typo & parameter data type --- docs/CH08.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/CH08.md b/docs/CH08.md index ed9ce05..01f7ee7 100644 --- a/docs/CH08.md +++ b/docs/CH08.md @@ -643,7 +643,7 @@ public class CloneDemo { public class ConcreteCircle { private double radius; - public void setRedius(int radius) { this.radius = radius; } + public void setRadius(double radius) { this.radius = radius; } public double getRadius() { return radius; } public void render() { System.out.printf("畫一個半徑 %f 的實心圓\n", getRadius()); @@ -652,7 +652,7 @@ public class CloneDemo { public class HollowCircle { private double radius; - public void setRedius(int radius) { this.radius = radius; } + public void setRadius(double radius) { this.radius = radius; } public double getRadius() { return radius; } public void render() { System.out.printf("畫一個半徑 %f 的空心圓\n", getRadius()); @@ -666,7 +666,7 @@ public class CloneDemo { public abstract class AbstractCircle { protected double radius; - public void setRedius(int radius) { this.radius = radius; } + public void setRadius(double radius) { this.radius = radius; } public double getRadius() { return radius; } public abstract void render(); From 79168b7708a0833ce5fc427fc2f6e15553dba116 Mon Sep 17 00:00:00 2001 From: obelisk0114 Date: Mon, 2 Jul 2018 21:50:41 -0700 Subject: [PATCH 12/24] Change some style and adjust space --- docs/CH20.md | 32 ++++++++++++++++---------------- docs/CH21.md | 46 ++++++++++++++++++++++++++++------------------ 2 files changed, 44 insertions(+), 34 deletions(-) diff --git a/docs/CH20.md b/docs/CH20.md index e415d08..ba162f9 100644 --- a/docs/CH20.md +++ b/docs/CH20.md @@ -10,9 +10,9 @@ JDBC(Java DataBase Connectivity)是用於執行 SQL 的 Java 解決方案, 在正式使用 JDBC 進行資料庫操作之前,先來認識一下 JDBC 的基本架構,了解資料庫驅動程式與資料庫之間的關係,在這個小節也將看到,如何設計一個簡單的工具類別,讓您在進行資料庫連接(Connection)時更為方便。 -20.1.1 簡介 JDBC +### 20.1.1 簡介 JDBC -如果要連接資料庫並進行操作,基本上必須了解所使用的資料庫所提供的 API 操作介面,然而各個廠商所提供的 API 操作介面並不一致,如果今天要使用A廠商的資料庫,就必須設計一個專用的程式來操作 A 廠商資料庫所提供的 API,將來如果要使用 B 廠商的資料庫,即使目的相同,也是要撰寫專用於 B 廠商資料庫之程式,十分的不方便。 +如果要連接資料庫並進行操作,基本上必須了解所使用的資料庫所提供的 API 操作介面,然而各個廠商所提供的 API 操作介面並不一致,如果今天要使用 A 廠商的資料庫,就必須設計一個專用的程式來操作 A 廠商資料庫所提供的 API,將來如果要使用 B 廠商的資料庫,即使目的相同,也是要撰寫專用於 B 廠商資料庫之程式,十分的不方便。 使用 JDBC,可由廠商實作操作資料庫介面的驅動程式,而 Java 程式設計人員呼叫 JDBC 的 API 並操作 SQL,實際對資料庫的操作由 JDBC 驅動程式負責,如果要更換資料庫,基本上只要更換驅動程式,Java 程式中只要載入新的驅動程式來源即可完成資料庫的變更,Java 程式的部份則無需改變。 @@ -62,7 +62,7 @@ JDBC 資料庫驅動程式依實作方式可以分為四個類型: ### 20.1.2 連接資料庫 -為了要連接資料庫系統,您必須要有JDBC驅動程式,由於接下來將使用 MySQL 資料庫進行操作,所以請將下載回來的tar.gz檔案使用解壓縮軟體解開,並將當中的 mysql-connector-java-*.jar 加入至 Classpath 的設定之中,假設是放在 c:\workspace\library\mysql-connector-java-3.1.13-bin.jar,則 Classpath 中必須有 c:\workspace\library\mysql-connector-java-3.1.13-bin.jar 這個路徑設定。 +為了要連接資料庫系統,您必須要有JDBC驅動程式,由於接下來將使用 MySQL 資料庫進行操作,所以請將下載回來的 tar.gz 檔案使用解壓縮軟體解開,並將當中的 mysql-connector-java-*.jar 加入至 Classpath 的設定之中,假設是放在 c:\workspace\library\mysql-connector-java-3.1.13-bin.jar,則 Classpath 中必須有 c:\workspace\library\mysql-connector-java-3.1.13-bin.jar 這個路徑設定。 在 Java SE 中與資料庫操作相關的 JDBC 類別都位於 java.sql 套件中,要連接資料庫,基本上必須有幾個動作: @@ -83,7 +83,7 @@ JDBC 資料庫驅動程式依實作方式可以分為四個類型: 協定:子協定:資料來源識別 - 「協定」在 JDBC 中總是 jdbc 開始;「子協定」是橋接的驅動程式或是資料庫管理系統名稱,使用 MySQL 的話是 "mysql";「資料來源識別」標出找出資料庫來源的位址與連接埠。舉個例子來說,MySQL 的 JDBC URL 撰寫方式如下: + 「協定」在 JDBC 中總是 jdbc 開始;「子協定」是橋接的驅動程式或是資料庫管理系統名稱,使用 MySQL 的話是 `mysql`;「資料來源識別」標出找出資料庫來源的位址與連接埠。舉個例子來說,MySQL 的 JDBC URL 撰寫方式如下: jdbc:mysql://主機名稱:連接埠/資料庫名稱?參數=值&參數=值 @@ -126,7 +126,7 @@ getConnection() 方法可以在參數上指定使用者名稱與密碼,例如 您可以將 JDBC URL、使用者名稱與密碼等設定資訊,撰寫在一個屬性檔案當中,由程式讀取這個屬性檔中的資訊,如果需要變更資訊,則只要修改屬性檔即可,無須修改程式、重新編譯,在 Java SE 當中,屬性檔的讀取可以交給 java.util.Properties 類別。 -舉個實際的例子,假設您使用了以下的指令在MySQL後建立了demo資料庫: +舉個實際的例子,假設您使用了以下的指令在 MySQL 後建立了 demo 資料庫: CREATE DATABASE demo; @@ -192,7 +192,7 @@ public class SimpleDBSource implements DBSource { } ``` -預設的建構方法設定中,是讀取 jdbc.properties 檔案中的設定,如果打算自行指定屬性檔案名稱,則可以使用另一個有參數的建構方法。Properties 的 getProperty() 方法會讀取屬性檔案中的"鍵(Key)"對應的"值(Value)",假設您的屬性檔案設定如下: +預設的建構方法設定中,是讀取 jdbc.properties 檔案中的設定,如果打算自行指定屬性檔案名稱,則可以使用另一個有參數的建構方法。Properties 的 getProperty() 方法會讀取屬性檔案中的 **鍵(Key)** 對應的 **值(Value)**,假設您的屬性檔案設定如下: #### **範例 20.3 jdbc.properties** ``` @@ -376,7 +376,7 @@ onlyfun.caterpillar.poolmax=10 Statement stmt = conn.createStatement(); -取得 Statement 物件之後,可以使用 executeUpdate()、executeQuery() 等方法來執行 SQL,executeUpdate() 主要是用來執行 CREATE TABLE、INSERT、DROP TABLE、ALTER TABLE 等會改變資料庫內容的 SQL,例如可以在 demo 資料庫中建立一個 t_message 表格: +取得 Statement 物件之後,可以使用 executeUpdate()、executeQuery() 等方法來執行 SQL,executeUpdate() 主要是用來執行 CREATE TABLE、INSERT、DROP TABLE、ALTER TABLE 等會改變資料庫內容的 SQL,例如可以在 demo 資料庫中建立一個 t_message 表格: Use demo; CREATE TABLE t_message ( @@ -413,7 +413,7 @@ Statement 的 executeQuery() 方法則是用於 SELECT 等查詢資料庫的 SQL System.out.print(result.getString(4) + "\t"); } -Statement 的 execute() 可以用來執行 SQL,並可以測試所執行的 SQL 是執行查詢或是更新,傳回 true 的話表示 SQL 執行將傳回 ResultSet 表示查詢結果,此時可以使用 getResultSet() 取得 ResultSet 物件,如果 execute() 傳回 false,表示 SQL 執行會傳回更新筆數或沒有結果,此時可以使用 getUpdateCount() 取得更新筆數。如果事先無法得知是進行查詢或是更新,就可以使用 execute()。 +Statement 的 execute() 可以用來執行 SQL,並可以測試所執行的 SQL 是執行查詢或是更新,傳回 true 的話表示 SQL 執行將傳回 ResultSet 表示查詢結果,此時可以使用 getResultSet() 取得 ResultSet 物件,如果 execute() 傳回 false,表示 SQL 執行會傳回更新筆數或沒有結果,此時可以使用 getUpdateCount() 取得更新筆數。如果事先無法得知是進行查詢或是更新,就可以使用 execute()。 範例 20.8 是個示範新增與查詢資料的範例,當中使用了前一節設計的 SimpleDBSource。注意在查詢結束後,要使用 Statement 的 close() 方法來釋放 Statement 的資源,而最後不使用連接時,也使用了 closeConnection() 來關閉連接。 @@ -580,7 +580,7 @@ public class PreparedStatementDemo { } ``` -setXXX() 方法的第一個參數指定"?"的位置,而第二個參數為要新增至資料表欄位的值,要讓 SQL 執行生效,要執行 executeQuery() 或 executeUpdate() 方法,使用 setXXX() 來設定的參數會一直有效,可以於下一次使用,如果想要清除設定好的參數,可以執行 clearParameters() 方法。以下是這個範例的執行結果參考: +setXXX() 方法的第一個參數指定 "?" 的位置,而第二個參數為要新增至資料表欄位的值,要讓 SQL 執行生效,要執行 executeQuery() 或 executeUpdate() 方法,使用 setXXX() 來設定的參數會一直有效,可以於下一次使用,如果想要清除設定好的參數,可以執行 clearParameters() 方法。以下是這個範例的執行結果參考: 1 justin justin@mail.com mesage... 2 momor momor@mail.com message2... @@ -612,7 +612,7 @@ fin.close(); 如果要從資料庫中取得 BLOB 或 CLOB 資料,您可以如下進行,其中 result 參考一個 ResultSet 的實例: Blob blob = result.getBlob(2); // 取得BLOB - Clob clob = result.getClob(2) // 取得CLOB + Clob clob = result.getClob(2); // 取得CLOB Blob 擁有 getBinaryStream()、getBytes() 等方法,可以取得二進位串流或 byte 等資料,同樣的,Clob 擁有 getCharacterStream()、getSubString() 等方法,可以取得字元串流或子字串等資料,您可以查看 API 文件來獲得更詳細的訊息。 @@ -736,9 +736,9 @@ public class LobDemo { 交易是一組原子(Atomic)操作(一組 SQL 執行)的工作單元,這個工作單元中的所有原子操作在進行期間,與其它交易隔離,免於數據來源的交相更新而發生混亂,交易中的所有原子操作,要嘛全部執行成功,要嘛全部失敗(即使只有一個失敗,所有的原子操作也要全部撤消)。 -舉個簡單的例子,一個客戶從 A 銀行轉帳至 B 銀行,要做的動作為從A銀行的帳戶扣款、在 B 銀行的帳戶加上轉帳的金額,兩個動作必須成功,如果有一個動作失敗,則此次轉帳失敗。 +舉個簡單的例子,一個客戶從 A 銀行轉帳至 B 銀行,要做的動作為從 A 銀行的帳戶扣款、在 B 銀行的帳戶加上轉帳的金額,兩個動作必須成功,如果有一個動作失敗,則此次轉帳失敗。 -在 JDB C中,可以操作 Connection 的 setAutoCommit() 方法,給它 false 引數,在下達一連串的 SQL 語句後,自行呼叫 Connection 的 commit() 來送出變更,如果中間發生錯誤,則呼叫 rollback() 來撤消所有的執行,一個示範的流程如下所示: +在 JDBC 中,可以操作 Connection 的 setAutoCommit() 方法,給它 false 引數,在下達一連串的 SQL 語句後,自行呼叫 Connection 的 commit() 來送出變更,如果中間發生錯誤,則呼叫 rollback() 來撤消所有的執行,一個示範的流程如下所示: ```java try { @@ -762,7 +762,7 @@ try { } ``` -如果您在交易管理時,僅想要撤回(rollback)某個SQL執行點,則您可以設定儲存點(save point),例如: +如果您在交易管理時,僅想要撤回(rollback)某個 SQL 執行點,則您可以設定儲存點(save point),例如: ```java conn.setAutoCommit(false); @@ -789,7 +789,7 @@ stmt.releaseSavepoint(savepoint); ### 20.2.6 批次處理 -Statement 的 execute 等方法一次只能執行一個 SQL 敘述,如果有多個 SQL 敘述要執行的話,可以使用 executeBatch() 方法,在一次方法呼叫中執行多個 SQL 敘述,以增加執行的效能,您可以使用 addBatch() 方法將要執行的 SQL 敘述加入,然後執行 executeBatch() 即可: +Statement 的 execute 等方法一次只能執行一個 SQL 敘述,如果有多個 SQL 敘述要執行的話,可以使用 executeBatch() 方法,在一次方法呼叫中執行多個 SQL 敘述,以增加執行的效能,您可以使用 addBatch() 方法將要執行的 SQL 敘述加入,然後執行 executeBatch() 即可: ```java conn.setAutoCommit(false); @@ -802,7 +802,7 @@ stmt.executeBatch(); conn.commit(); ``` -在執行 executeBatch() 時而 SQL 有錯誤的情況下,會丟出 BatchUpdateException 例外,您可以由這個例外物件的 getUpdateCounts() 方法取得發生錯誤的SQL句數,如果中間有個 SQL 執行錯誤,則應該撤回(rollback)整個批次處理過程的SQL操作。 +在執行 executeBatch() 時而 SQL 有錯誤的情況下,會丟出 BatchUpdateException 例外,您可以由這個例外物件的 getUpdateCounts() 方法取得發生錯誤的 SQL 句數,如果中間有個 SQL 執行錯誤,則應該撤回(rollback)整個批次處理過程的 SQL 操作。 使用 PreparedStatement 也可以進行批次處理,直接來看個例子: @@ -947,7 +947,7 @@ relative() 方法則從目前游標處指定相對位置,例如若目前在第 ### 20.2.9 ResultSetMetaData -Meta Data 即「資料的資料」(Data about data),ResultSet 用來表示查詢到的資料,而 ResultSe t資料的資料,即描述所查詢到的資料背後的資料描述,即用來表示表格名稱、欄位名稱、欄位型態等,這些訊息可以透過 ResultSetMetaData 來取得。 +Meta Data 即「資料的資料」(Data about data),ResultSet 用來表示查詢到的資料,而 ResultSet 資料的資料,即描述所查詢到的資料背後的資料描述,即用來表示表格名稱、欄位名稱、欄位型態等,這些訊息可以透過 ResultSetMetaData 來取得。 範例 20.12 直接示範如何取得查詢到的資料欄位數、表格名稱、欄位名稱與欄位資料型態: diff --git a/docs/CH21.md b/docs/CH21.md index 793ebbd..561424e 100644 --- a/docs/CH21.md +++ b/docs/CH21.md @@ -115,7 +115,7 @@ public class BinarySearchDemo { } ``` -在這個程式中,指定搜尋索引 6 到索引 9(不包括索引 9)的範圍中是否有 85 的值,如果找到的話,傳回索引值,如果沒有找到,傳回一個負值,該負值加 1 再乘以 -1,就是插入點位置,也就是第一個比指定搜尋值大的值之索引位置,就這個程式而言,就是顯示 "插入點8" 的結果。 +在這個程式中,指定搜尋索引 6 到索引 9(不包括索引 9)的範圍中是否有 85 的值,如果找到的話,傳回索引值,如果沒有找到,傳回一個負值,該負值加 1 再乘以 -1,就是插入點位置,也就是第一個比指定搜尋值大的值之索引位置,就這個程式而言,就是顯示 "插入點 8" 的結果。 在 18.1.2 使用 Calendar 中,在範例 18.6 中使用 switch 進行判斷以顯示中文的日期格式,在 Java SE 6 中,您可以直接使用 getDisplayNames() 或 getDisplayName() 方法取得區域化的日期格式顯示,例如可以改寫範例 18.6 為以下的程式: @@ -154,7 +154,7 @@ public class CalendarDemo { 23 日 星期四 -在 Java SE 6 中,對於集合物件還增加有 Deque 介面(繼承自Queue介面)、NavigableMap 介面(繼承自 SortedMap 介面)、NavigableSet 介面(繼承自 SortedSet 介面),建議您可以查閱一下 API 文件,以了解這些集合物件的使用方式。 +在 Java SE 6 中,對於集合物件還增加有 Deque 介面(繼承自 Queue 介面)、NavigableMap 介面(繼承自 SortedMap 介面)、NavigableSet 介面(繼承自 SortedSet 介面),建議您可以查閱一下 API 文件,以了解這些集合物件的使用方式。 ### 21.1.3 java.io 套件 @@ -266,7 +266,7 @@ public class FileDemo { 在 Java SE 6 中對於視窗程式設計也作了極大的改進,雖然本書並沒有深入講解 Java 的視窗程式設計,然而在這邊可以介紹幾個有特色且使用簡單的功能。 -有些視窗程式在啟動時,會有個啟動畫面,在 Java SE 6 之前,您要自己實作才可以擁有這個功能,現在您可以直接在使用 "java" 程式執行程式時下達 "-splash" 引數指定啟動畫面的圖片,就可以擁有這個功能,例如若執行 19.5 所製作出來的 Executable Jar 檔時,如下指定圖片: +有些視窗程式在啟動時,會有個啟動畫面,在 Java SE 6 之前,您要自己實作才可以擁有這個功能,現在您可以直接在使用 "java" 程式執行程式時下達 `-splash` 引數指定啟動畫面的圖片,就可以擁有這個功能,例如若執行 19.5 所製作出來的 Executable Jar 檔時,如下指定圖片: java -splash:caterpillar.jpg -jar JNotePad.jar @@ -276,13 +276,13 @@ public class FileDemo { 圖 21.1 指定啟動畫面的執行結果 -您也可以在製作 Executable JAR 檔案時,於 manifest 檔案中指定 "SplashScreen-Image" 為啟動畫面的圖片,並在使用 jar 程式進行包裝時一併包裝圖片,如此啟動 JAR 檔案時,就會自動展現啟動畫面,一個 manifest 檔案的寫法如下所示: +您也可以在製作 Executable JAR 檔案時,於 manifest 檔案中指定 `SplashScreen-Image` 為啟動畫面的圖片,並在使用 jar 程式進行包裝時一併包裝圖片,如此啟動 JAR 檔案時,就會自動展現啟動畫面,一個 manifest 檔案的寫法如下所示: Manifest-Version: 1.0 Main-Class: onlyfun.caterpillar.JNotePad SplashScreen-Image: caterpillar.jpg -如果您對於啟動畫面更進一步的控制感興趣,例如在不同的啟動階段顯示不同的圖片,或者是在啟動圖片上顯示進度列,則可以看看 java.awt. SplashScreen 的 API 文件說明。 +如果您對於啟動畫面更進一步的控制感興趣,例如在不同的啟動階段顯示不同的圖片,或者是在啟動圖片上顯示進度列,則可以看看 java.awt.SplashScreen 的 API 文件說明。 在 Java SE 6 中加入了系統工具列圖示的支援,您可以使用 SystemTray 類別的 isSupported() 方法,測試看看目前的系統是否支援系統工具列圖示,如果支援的話,可以使用 getSystemTray() 取得 SystemTray 實例,使用 add() 方法加入 TrayIcon 實例,如此就可以加入一個系統工具列圖示,例如: @@ -357,8 +357,9 @@ public class SystemTrayDemo2 { 圖 21.3 系統工具列蹦現視窗 -如果要移除系統工具列中的圖示,則可以使用SystemTray實例的remove()方法,指定要移除的圖示,例如: -tray.remove(trayIcon); +如果要移除系統工具列中的圖示,則可以使用 SystemTray 實例的 remove() 方法,指定要移除的圖示,例如: + + tray.remove(trayIcon); ### 21.1.5 Classpath 簡化設定 @@ -380,7 +381,7 @@ Java SE 6 中包含了 JDBC 4.0,對於 JDBC 的使用有了相當的簡化, 目前對於 JDBC 4.0 支援的資料庫驅動程式還不多,在 JDK 6 中綑綁了 [Apache Derby 資料庫](http://db.apache.org/derby/),這是一個純 Java 撰寫的資料庫,支援 JDBC 4.0,您可以在 JDK 6 包裝目錄的 db 目錄下找到 Apache Derby 的相關檔案,也可以至 http://db.apache.org/derby/derby_downloads.html 下載 Apache Derby 資料庫,所下載的檔案中將包括更多的文件等相關資源。 -使用 Apache Derby 資料庫最簡單的方式之一,是使用 NetBeans IDE 來啟動、連接、管理 Derby 資料庫,您可以在 [Sun 官方網站](http://java.sun.com),或是 [NetBeans官方網站](http://www.netbeans.org/) 下載最新的 NetBeans IDE 並進行安裝,在這邊將以 NetBeans IDE 5.5 來示範,如何使用 Derby 資料庫。 +使用 Apache Derby 資料庫最簡單的方式之一,是使用 NetBeans IDE 來啟動、連接、管理 Derby 資料庫,您可以在 [Oracle 官方網站](http://www.oracle.com/technetwork/java/index.html),或是 [NetBeans 官方網站](http://www.netbeans.org/) 下載最新的 NetBeans IDE 並進行安裝,在這邊將以 NetBeans IDE 5.5 來示範,如何使用 Derby 資料庫。 首先,請啟動 NetBeans IDE,執行選單上的「Tools/Options」,接著選擇「Advanced Options」,在「IDE Configuration」中選擇「Server and External Tool Settings」的「Java DB Database」,接著在右邊的「Java DB Location」中設定 Apache Derby 的位置,在這邊是指向「C:\Program Files\Java\jdk1.6.0\db」,而在「Database Location」中設定您的資料庫儲存位置,在這邊是設定為「C:\workspace\database」,如下圖所示: @@ -430,23 +431,32 @@ Java SE 6 中包含了 JDBC 4.0,對於 JDBC 的使用有了相當的簡化, 圖 21.11 查詢表格資料 -關於Apache Derby的介紹先到這邊告一段落,接下來將要介紹,如何撰寫程式連接Apache Derby,並使用JDBC 4.0的新功能。 +關於 Apache Derby 的介紹先到這邊告一段落,接下來將要介紹,如何撰寫程式連接 Apache Derby,並使用 JDBC 4.0 的新功能。 + +### 21.2.2 載入驅動程式 + +在之前的操作中,可以從圖中看到,要連接 Apache Derby,使用的 JDBC URL 是 "jdbc:derby://localhost:1527/demo",而 Apache Derby 的 JDBC 驅動程式是放在 derbyclient.jar 之中,因此請記得在您的 Classpath 之中加以設定。 -21.2.2 載入驅動程式 -在之前的操作中,可以從圖中看到,要連接Apache Derby,使用的JDBC URL是" jdbc:derby://localhost:1527/demo",而Apache Derby的JDBC驅動程式是放在derbyclient.jar之中,因此請記得在您的Classpath之中加以設定。 -在JDBC 4.0之前,如果您要連接資料庫的話,必須使用Class.forName()並指定驅動程式類別名稱,以載入JDBC驅動程式,例如: +在 JDBC 4.0 之前,如果您要連接資料庫的話,必須使用 Class.forName() 並指定驅動程式類別名稱,以載入 JDBC 驅動程式,例如: + +``` String url = …; String username = …; String password = …; String driver = …; Class.forName(driver); Connection conn = DriverManager.getConnection(url, username, password); -在JDBC 4.0之中,不需要再呼叫Class.forName()並指定驅動程式了,也就是說,只要一行就可以了: -Connection conn = DriverManager.getConnection(url, username, password); -那麼JVM如何得知要載入哪個驅動程式呢?JVM會自動在Classpath中尋找適當的驅動程式,在包裝有JDBC驅動程式的JAR檔案中,必須有一個"META-INF/services/java.sql.Driver"檔案,當中撰寫驅動程式類別名稱,以Apache Derby為例,在derbyclient.jar中的"META-INF/services/java.sql.Driver"檔案中,撰寫的是"org.apache.derby.jdbc.ClientDriver "。 -以第20章的範例20.2為例,若使用JDBC 4.0,則可以將Class.forName()該行移除,並在執行時指定Classpath中包括derbyclient.jar的位置,而範例20.4仍然正常運行。 +``` + +在 JDBC 4.0 之中,不需要再呼叫 Class.forName() 並指定驅動程式了,也就是說,只要一行就可以了: + + Connection conn = DriverManager.getConnection(url, username, password); + +那麼 JVM 如何得知要載入哪個驅動程式呢? JVM 會自動在 Classpath 中尋找適當的驅動程式,在包裝有 JDBC 驅動程式的 JAR 檔案中,必須有一個 `META-INF/services/java.sql.Driver` 檔案,當中撰寫驅動程式類別名稱,以 Apache Derby 為例,在 derbyclient.jar 中的 `META-INF/services/java.sql.Driver` 檔案中,撰寫的是 `org.apache.derby.jdbc.ClientDriver`。 + +以第 20 章的範例 20.2 為例,若使用 JDBC 4.0,則可以將 Class.forName() 該行移除,並在執行時指定 Classpath 中包括 derbyclient.jar 的位置,而範例 20.4 仍然正常運行。 -### 21.2.2 改進的例外處理 +### 21.2.3 改進的例外處理 在 JDBC 4.0 之中,SQLException 新增了幾個建構函式,可以接受 Throwable 實例進行 SQLException 的建構,您可以重新將某個例外包裝為 SQLException,例如由於 IOException 發生的 SQLException,這表示您對於 SQLException 所發生的原因更加可以細分與掌握,SQLException 並實作了 `Iterable` 介面,現在您可以在捕捉到 SQLException 時,使用加強的 for 迴圈來找出例外發生的原因,例如: @@ -468,7 +478,7 @@ catch(SQLException ex) { SQLException 在 JDBC 4.0 中多了幾個子類別,針對不同的錯誤將例外加以細分,您可以查看 API 文件中有關 SQLException 的說明。 -### 21.2.3 BLOB、CLOB 的改進 +### 21.2.4 BLOB、CLOB 的改進 在 20.2.3 中介紹過 JDBC 的 LOB 讀寫,當需要存入資料至 BLOB 或 CLOB 欄位時,要使用 PreparedStatement 的 setBinaryStream()、 setObject()、setAsciiStream()、setUnicodeStream() 等方法,在 API 名稱上並不是很明確。 From d4de1ab5995e6cd6226d33e0eac7c6b339db84fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=B3=E9=98=B3?= <260893248@qq.com> Date: Wed, 1 Aug 2018 19:43:28 +0800 Subject: [PATCH 13/24] fix typo "parametar" -> "parameter" --- docs/CH17.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CH17.md b/docs/CH17.md index 9adecf2..736d487 100644 --- a/docs/CH17.md +++ b/docs/CH17.md @@ -407,7 +407,7 @@ Annotation 標示於方法上的話,就要取得方法的 Method 代表實例 TYPE, // 適用 class, interface, enum FIELD, // 適用 field METHOD, // 適用 method - PARAMETER, // 適用 method 上之 parametar + PARAMETER, // 適用 method 上之 parameter CONSTRUCTOR, // 適用 constructor LOCAL_VARIABLE, // 適用區域變數 ANNOTATION_TYPE, // 適用 annotation 型態 From 44013f650306dc21706c7468b70c792d3cd89cbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=B3=E9=98=B3?= <260893248@qq.com> Date: Thu, 2 Aug 2018 13:20:28 +0800 Subject: [PATCH 14/24] fix small syntax error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. remove "的" 2. "別" -> "類別" --- docs/CH16.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CH16.md b/docs/CH16.md index 4d632b5..63459cb 100644 --- a/docs/CH16.md +++ b/docs/CH16.md @@ -52,7 +52,7 @@ public class ClassDemo { Class stringClass = String.class; -Java 在真正需要類別時才會載入類別,所謂「真正需要」通常指的是要使用指定的類別生成物件時(或是使用者指定要載入類別時,例如使用 Class.forName() 載入類別,或是使用 ClassLoader 的 loadClass() 載入類別,稍後都會說明)。使用類別名稱來宣告參考名稱並不會導致類別的載入,可以設計一個測試類別的印證這個說法。 +Java 在真正需要類別時才會載入類別,所謂「真正需要」通常指的是要使用指定的類別生成物件時(或是使用者指定要載入類別時,例如使用 Class.forName() 載入類別,或是使用 ClassLoader 的 loadClass() 載入類別,稍後都會說明)。使用類別名稱來宣告參考名稱並不會導致類別的載入,可以設計一個測試類別印證這個說法。 #### **範例 16.2 TestClass.java** ```java @@ -475,7 +475,7 @@ onlyfun.caterpillar.SomeClass 是個自訂類別,您在目前的工作目錄 由於 SomeClass 這次可以在 Bootstrap Loader 的設定路徑下找到,所以會由 Bootstrap Loader 來載入 SomeClass 類別,Bootstrap Loader 通常由 C 撰寫而成,在 Java 中沒有一個實際的類別來表示,所以顯示為 null,因為表示為 null,所以再 由 null 上嘗試呼叫 getParent() 方法就會丟出 NullPointerException 例外。 -取得 ClassLoader 的實例之後,您可以使用它的 loadClass() 方法來載入類別,使用 loadClass() 方法載入別時,不會執行靜態區塊,靜態區塊的執行會等到真正使用類別來建立實例時,例如您可以改寫範例 16.7 為範例 16.12。 +取得 ClassLoader 的實例之後,您可以使用它的 loadClass() 方法來載入類別,使用 loadClass() 方法載入類別時,不會執行靜態區塊,靜態區塊的執行會等到真正使用類別來建立實例時,例如您可以改寫範例 16.7 為範例 16.12。 #### **範例 16.12 ForNameDemoV3.java** ```java From b5bf48a8c2e17b616068e3e665bbc60d29265ef7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=B3=E9=98=B3?= <260893248@qq.com> Date: Sat, 4 Aug 2018 16:37:20 +0800 Subject: [PATCH 15/24] fix typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. "是有些" -> "有些是" 2. "Unckecked" -> "Unchecked" --- docs/CH10.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CH10.md b/docs/CH10.md index bff504a..3e4ea4d 100644 --- a/docs/CH10.md +++ b/docs/CH10.md @@ -273,7 +273,7 @@ Error 類別與 Exception 類別都繼承自 Throwable 類別,Throwable 類別 除了使用這些方法之外,您也可以簡單的利用例外物件 toString() 方法取得例外的簡單訊息描述。 -您所接觸的例外通常都是衍生自 Exception 類別,其中是有些「受檢例外」(Checked exception),例如 ClassNotFoundException(嘗試載入類別時失敗所引發,例如類別檔案不存在)、InterruptedException(執行緒非執行中而嘗試中斷所引發的例外)等,而有些是「執行時期例外」(Runtime exception),也稱「非受檢例外」(Unckecked exception),例如 ArithmeticException、ArrayIndexOutOfBoundsException 等。以下列出一些重要的例外繼承架構: +您所接觸的例外通常都是衍生自 Exception 類別,其中有些是「受檢例外」(Checked exception),例如 ClassNotFoundException(嘗試載入類別時失敗所引發,例如類別檔案不存在)、InterruptedException(執行緒非執行中而嘗試中斷所引發的例外)等,而有些是「執行時期例外」(Runtime exception),也稱「非受檢例外」(Unchecked exception),例如 ArithmeticException、ArrayIndexOutOfBoundsException 等。以下列出一些重要的例外繼承架構: Throwable   Error(嚴重的系統錯誤) From ccb37f8636e05f2c615e7e5e13ffa9eb4fc7c53c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=B3=E9=98=B3?= <260893248@qq.com> Date: Tue, 2 Oct 2018 18:28:10 +0800 Subject: [PATCH 16/24] fix some typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修改拼写错误 --- docs/CH14.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/CH14.md b/docs/CH14.md index ef56a1a..851d05f 100644 --- a/docs/CH14.md +++ b/docs/CH14.md @@ -297,7 +297,7 @@ public class StreamDemo { ### 14.2.2 FileInputStream、FileOutputStream -java.io.FileInputStream 是 InputStream 的子類,由開頭 File 名稱上就可以知道,FileInputStream 與從指定的檔案中讀取資料至目的地有關,而 java.io.FileOutputStream 是 OutputStream 的子類,顧名思義,FileOnputStream 主要與從來源地寫入資料至指定的檔案中有關。 +java.io.FileInputStream 是 InputStream 的子類,由開頭 File 名稱上就可以知道,FileInputStream 與從指定的檔案中讀取資料至目的地有關,而 java.io.FileOutputStream 是 OutputStream 的子類,顧名思義,FileOutputStream 主要與從來源地寫入資料至指定的檔案中有關。 當您建立一個 FileInputStream 或 FileOutputStream 的實例時,必須指定檔案位置及檔案名稱,實例被建立時檔案的串流就會開啟,而不使用串流時,您必須關閉檔案串流,以釋放與串流相依的系統資源,完成檔案讀寫的動作。 @@ -751,7 +751,7 @@ public class ObjectStreamDemo { momor 103 becky 104 -注意在試圖將物件附加至一個先前已寫入物件的檔案時,由於 ObjectOutputStream 在寫入資料時,還會加上一個特別的串流頭(Stream header),而讀取檔案時會檢查這個串流頭,如果一個檔案中被多次附加物件,那麼該檔案中會有多個串流頭,如此讀取檢查時就會發現不一致,這會丟出 java.io.StreamCorrupedException,為了解決這個問題,您可以重新定義 ObjectOutputStream 的 writeStreamHeader() 方法,如果是以附加的方式來寫入物件,就不寫入串流頭: +注意在試圖將物件附加至一個先前已寫入物件的檔案時,由於 ObjectOutputStream 在寫入資料時,還會加上一個特別的串流頭(Stream header),而讀取檔案時會檢查這個串流頭,如果一個檔案中被多次附加物件,那麼該檔案中會有多個串流頭,如此讀取檢查時就會發現不一致,這會丟出 java.io.StreamCorruptedException,為了解決這個問題,您可以重新定義 ObjectOutputStream 的 writeStreamHeader() 方法,如果是以附加的方式來寫入物件,就不寫入串流頭: ObjectOutputStream objOutputStream = new ObjectOutputStream( @@ -973,7 +973,7 @@ public class PrintStreamDemo { ### 14.2.8 ByteArrayInputStream、ByteArrayOutputStream -串流的來源或目的地不一定是檔案,也可以是記憶體中的一個空間,例如一個位元陣列,java.io.ByteArrayInputStream、java.io.ByteArray OutputStream 即是將位元陣列當作串流輸入來源、輸出目的地的類別。 +串流的來源或目的地不一定是檔案,也可以是記憶體中的一個空間,例如一個位元陣列,java.io.ByteArrayInputStream、java.io.ByteArrayOutputStream 即是將位元陣列當作串流輸入來源、輸出目的地的類別。 ByteArrayInputStream 可以將一個陣列當作串流輸入的來源,而 ByteArrayOutputStream 則可以將一個位元陣列當作串流輸出的目的地,在這邊舉一個簡單的檔案位元編輯程式作為例子,您可以開啟一個簡單的文字檔案,當中有簡單的 ABCDEFG 等字元,在讀取檔案之後,您可以直接以程式來指定檔案中位元的位置來修改所指定的字元,作法是將檔案讀入陣列中,指定陣列索引修改元素,然後重新將陣列存回檔案,範例 14.14 是實作的程式內容。 From b6180ca5308f717ee174e801321faf872e23d806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=B3=E9=98=B3?= <260893248@qq.com> Date: Tue, 1 Jan 2019 21:18:12 +0800 Subject: [PATCH 17/24] 18->20 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 似乎是因為 Internationalization 這個單詞總共有20個字母,那麼第一個字母 I 和最後一個字母 n 之間有 18 個字母,所以才會被簡稱為 I18N 的。而且我試了下,Internationalization 的長度確實是 20 --- docs/CH18.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CH18.md b/docs/CH18.md index 380057d..a01db78 100644 --- a/docs/CH18.md +++ b/docs/CH18.md @@ -825,7 +825,7 @@ public class MessageFormatDemo { ### 18.3.3 國際化訊息 -國際化的英文是 Internationalization,因為單字中總共有18個字母而首尾字元分別為 'I' 與 'N',所以簡稱 I18N,國際化的目的是讓應用程式可以依地區不同而顯示不同的訊息,最基本的就是讓不同語系的使用者可以看到屬於自己語系的訊息,像是英文語系的看到英文內容,而中文語系的可以看到中文的內容。 +國際化的英文是 Internationalization,因為單字中總共有20個字母而首尾字元分別為 'I' 與 'N',所以簡稱 I18N,國際化的目的是讓應用程式可以依地區不同而顯示不同的訊息,最基本的就是讓不同語系的使用者可以看到屬於自己語系的訊息,像是英文語系的看到英文內容,而中文語系的可以看到中文的內容。 為了在應用程式中表示一個區域,Java 提供有 java.util.Locale 類,一個 Locale 實例包括了語系資訊與區域資訊,例如 "en" 表示英文語系的國家,這個字母組合是在 ISO 639 中定義的,而區域資訊則是像 "US" 表示美國,這個字母組合則是在 ISO 3166 中定義的。 From 55358d5b20833865c7c79991685fe089649c7360 Mon Sep 17 00:00:00 2001 From: obelisk0114 Date: Thu, 7 Mar 2019 02:13:03 -0800 Subject: [PATCH 18/24] Fix typo and adjust space --- docs/CH19.md | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/CH19.md b/docs/CH19.md index 8870d17..4745bca 100644 --- a/docs/CH19.md +++ b/docs/CH19.md @@ -1,6 +1,6 @@ # 第 19 章 專題製作 - 文字編輯器 -在學習完一個程式語言的基本語法、API 的使用之後,若要驗收學習的成果,試著自己撰寫一個文字編輯器是個不錯的驗收方式,在這個章節中將一步步告訴您,如何組合前面18個章節中學習到的語法及 API 功能,實作出一個具讀取、儲存功能的視窗文字編輯器。 +在學習完一個程式語言的基本語法、API 的使用之後,若要驗收學習的成果,試著自己撰寫一個文字編輯器是個不錯的驗收方式,在這個章節中將一步步告訴您,如何組合前面 18 個章節中學習到的語法及 API 功能,實作出一個具讀取、儲存功能的視窗文字編輯器。 在這個章節中,您也將學到基本的 Swing 視窗程式設計,了解 Java 的視窗程式中容器(Container)、元件(Component)、版面管理員(Layout Manager)、事件(Event)與傾聽者(Listener)的基本觀念。 @@ -16,7 +16,7 @@ - 具備視窗介面 - 您必須決定使用者將如何操作您的文字編輯器,這要考量使用者在操作上的習慣,或是領域(Domain)特有的操作需求,操作介面設計良好與否,對一個產品是否受歡迎有相當大的影響,您可以觀察所要開發的程式是否有相類似的產品,看看該產品是如何設計操作介面的,對於簡單的文字編輯器之開發,可以參考Windows的「記事本」程式在介面上是如何設計的。 + 您必須決定使用者將如何操作您的文字編輯器,這要考量使用者在操作上的習慣,或是領域(Domain)特有的操作需求,操作介面設計良好與否,對一個產品是否受歡迎有相當大的影響,您可以觀察所要開發的程式是否有相類似的產品,看看該產品是如何設計操作介面的,對於簡單的文字編輯器之開發,可以參考 Windows 的「記事本」程式在介面上是如何設計的。 您可以在紙上或繪圖軟體上,先設計出操作介面草稿,在設計介面的同時,也會大致勾勒出應用程式的部份功能,對於您將開發的文字編輯器,將具備以下的視窗介面: @@ -78,7 +78,7 @@ ### 19.1.3 開發(Development) -進入開發階段之後,將決定使用何種語言及技術來開發應用程式,在這個章節中,您將使用 Java 程式語言,並運用 Java SE 技術來開發文字編輯器,文字編輯器的介面將使用Swing視窗元件來開發,這也是這個章節所要著重的階段。 +進入開發階段之後,將決定使用何種語言及技術來開發應用程式,在這個章節中,您將使用 Java 程式語言,並運用 Java SE 技術來開發文字編輯器,文字編輯器的介面將使用 Swing 視窗元件來開發,這也是這個章節所要著重的階段。 ### 19.1.4 測試(Testing) @@ -102,7 +102,7 @@ ## 19.2 Swing 入門 -若要使用 Java SE 來開發視窗應用程式,就本書撰寫的時間點來說可以有兩種選擇,一個是使用 AWT(Abstract Window Toolkit),另一個是使用 JFC(Java Foundation Classes)/Swing。您所要開發的文字編輯器將使用 Swing 技術,Swing 的使用可以很複雜,是個可以用專書介紹的技術,而這個小節的目的,在讓您於開發文字編輯器的介面,同時也可以掌握 Swing 設計的最基本要素,也就是容器(Container)、元件(Component)、版面管理員(Layout Manager)、事件(Event)與傾聽者(Listener)等基本觀念。 +若要使用 Java SE 來開發視窗應用程式,就本書撰寫的時間點來說可以有兩種選擇,一個是使用 AWT(Abstract Window Toolkit),另一個是使用 JFC(Java Foundation Classes)/ Swing。您所要開發的文字編輯器將使用 Swing 技術,Swing 的使用可以很複雜,是個可以用專書介紹的技術,而這個小節的目的,在讓您於開發文字編輯器的介面,同時也可以掌握 Swing 設計的最基本要素,也就是容器(Container)、元件(Component)、版面管理員(Layout Manager)、事件(Event)與傾聽者(Listener)等基本觀念。 ### 19.2.1 Swing 簡介 @@ -161,7 +161,7 @@ Swing 的元件相當的豐富,若要詳細說明,實際上可以另外出 - 主視窗 -您可以繼承 javax.swing.JFrame 來撰寫一個可以呈現在螢幕上的視窗,最基本的動作包括:設定視窗元件、設定事件處理、呈現畫面。直接使用範例 19.1 來示範如何呈現一個基本的Swing視窗。 +您可以繼承 javax.swing.JFrame 來撰寫一個可以呈現在螢幕上的視窗,最基本的動作包括:設定視窗元件、設定事件處理、呈現畫面。直接使用範例 19.1 來示範如何呈現一個基本的 Swing 視窗。 #### **範例 19.1 JNotePadUI.java** ```java @@ -193,7 +193,7 @@ public class JNotePadUI extends JFrame { 在範例 19.1 中,將視窗元件的設置與事件的處理分別交由 setUpUIComponent() 與 setUpEventListener() 兩個方法來處理,這有助於將來程式碼內容增加時的管理。 -JFrame 擁有一個接受字串引數的建構方法,被設置的字串將用作視窗的標題文字,從 JFrame 繼承下來的 setSize() 方法用來設定視窗元件的大小,程式中設定為 640x480 的像素(Pixel)大小。setDefaultCloseOperation() 用來設定視窗右上角的X按鈕被按下時所該採取的動作,預設是 WindowConstants.HIDE_ONE_CLOSE,也就是按下後隱藏視窗,但並不會結束程式,在這邊希望按下X按鈕後可以直接結束程式,因而設定為 JFrame.EXIT_ON_CLOSE。 +JFrame 擁有一個接受字串引數的建構方法,被設置的字串將用作視窗的標題文字,從 JFrame 繼承下來的 setSize() 方法用來設定視窗元件的大小,程式中設定為 640x480 的像素(Pixel)大小。setDefaultCloseOperation() 用來設定視窗右上角的 X 按鈕被按下時所該採取的動作,預設是 WindowConstants.HIDE_ON_CLOSE,也就是按下後隱藏視窗,但並不會結束程式,在這邊希望按下 X 按鈕後可以直接結束程式,因而設定為 JFrame.EXIT_ON_CLOSE。 在所有的元件與事件處理都設置完成之後,可以使用從 JFrame 繼承下來的 setVisible(),藉由設定其引數為 true 來呈現視窗,程式的執行結果如下圖所示: @@ -350,7 +350,7 @@ public class JNotePadUI extends JFrame { 在 Container 中的元件的位置跟大小是由版面管理員(Layout manager)來決定,當 Container 需要決定它當中的元件的大小或位置時,就會呼叫版面管理員來為其執行。 -- JTextArea 與 JScorllPane +- JTextArea 與 JScrollPane 文字編輯器的基本需求,就是有一個文字編輯區域,這個文字編輯區域可以使用 javax.swing.JTextArea 類別,然而 JTextArea 並不具備捲軸,文字內容多時沒有捲軸對於編輯或瀏覽都不方便,您可以在 JTextArea 上加上一個 javax.swing.JScrollPane,JScrollPane 會檢驗 JTextArea 的文字內容,在必要的時候顯示捲軸,或者是在操作捲軸時,也會對 JTextArea 進行相對應的位置顯示,以下是結合 JTextArea、JScrollPane 以建立文字編輯區域的程式碼片段: @@ -464,7 +464,7 @@ public class JNotePadUI extends JFrame { ## 19.3 事件處理 -當使用者在圖形介面上進行一些操作時,例如移動滑鼠、選取選單項目等,將會引發相關事件(Event)的發生,在 Java 中事件以具體的物件來表示,使用者的相關動作會由JVM建立相對應的事件,用以描述事件來源、發生了什麼事、以及相關的訊息,您要藉由捕捉對應的事件,以進行對應的操作來完成應用程式的功能。 +當使用者在圖形介面上進行一些操作時,例如移動滑鼠、選取選單項目等,將會引發相關事件(Event)的發生,在 Java 中事件以具體的物件來表示,使用者的相關動作會由 JVM 建立相對應的事件,用以描述事件來源、發生了什麼事、以及相關的訊息,您要藉由捕捉對應的事件,以進行對應的操作來完成應用程式的功能。 ### 19.3.1 Java 事件模型 @@ -524,7 +524,7 @@ Java 對事件的處理採委託事件模型(Delegation event model),在 } ); -滑鼠處理者接受的是 MouseEvent,您可以使用 getButton() 方法取得一個常數,表示按下的是哪一個滑鼠鍵,MouseEvent.Button1 是指按下滑鼠左鍵,MouseEvent.Button3 則表示滑鼠右鍵,您使用 JTextArea的addMouseListener() 方法加入傾聽者,程式片段中的 popUpMenu 參考至 javax.swing.JPopupMenu 的實例,這個實例可用編輯選單直接取得,例如: +滑鼠處理者接受的是 MouseEvent,您可以使用 getButton() 方法取得一個常數,表示按下的是哪一個滑鼠鍵,MouseEvent.Button1 是指按下滑鼠左鍵,MouseEvent.Button3 則表示滑鼠右鍵,您使用 JTextArea 的 addMouseListener() 方法加入傾聽者,程式片段中的 popUpMenu 參考至 javax.swing.JPopupMenu 的實例,這個實例可用編輯選單直接取得,例如: JPopupMenu popUpMenu = editMenu.getPopupMenu(); @@ -728,7 +728,7 @@ public class JNotePadUI extends JFrame { ### 19.4.1 開啟檔案的流程處理 -首先定義出當使用者選取選單上的「開啟舊檔」時,所需的處理流程:先檢查目前編輯中的文件是否已儲存,若是,則希望出現對話方塊供使用者選取所需的檔案、開啟它然後顯示在文字編輯區;若否,則出現對話方塊顯示"檔案已修改,是否儲存?"的訊息,若選擇「是」則儲存檔案,若選擇「否」則放棄目前檔案直接開啟舊檔。 +首先定義出當使用者選取選單上的「開啟舊檔」時,所需的處理流程:先檢查目前編輯中的文件是否已儲存,若是,則希望出現對話方塊供使用者選取所需的檔案、開啟它然後顯示在文字編輯區;若否,則出現對話方塊顯示`檔案已修改,是否儲存?`的訊息,若選擇「是」則儲存檔案,若選擇「否」則放棄目前檔案直接開啟舊檔。 上面的流程中,可以分出幾個子流程,例如檢查檔案是否儲存、開啟文件、儲存檔案,這幾個子流程可以先定義為方法,待會再來實作,因此可以先實作出以下的程式內容: @@ -763,7 +763,7 @@ private boolean isCurrentFileSaved() { } ``` -JOptionPane.showConfirmDialog() 可以出現一個訊息對話方塊,設定 JOptionPane.YES_NO_OPTION 會出現「是」、「否」的按鈕,而設定 JOptionPane.WARNING_MESSAGE 會出現一個警告圖示,在確認是否之後,會得到一個 int 常數,與 JOptionPane.YES_OPTION 或 JOptionPane.YES_OPTION 比對,即可得知使用者按下了哪一個按鈕。 +JOptionPane.showConfirmDialog() 可以出現一個訊息對話方塊,設定 JOptionPane.YES_NO_OPTION 會出現「是」、「否」的按鈕,而設定 JOptionPane.WARNING_MESSAGE 會出現一個警告圖示,在確認是否之後,會得到一個 int 常數,與 JOptionPane.YES_OPTION 或 JOptionPane.NO_OPTION 比對,即可得知使用者按下了哪一個按鈕。 ![顯示是否的對話方塊](../images/img19-10.png) @@ -960,7 +960,7 @@ private void processTextArea() { 撰寫 Java 程式到這邊,相信您一定會有所疑問的是,編出來的 .class 檔案越來越多,難道要將這一堆 .class 檔案直接給想要執行程式的人嗎?在 Windows 下的話,有沒有辦法按一下檔案,就可以執行程式呢? -當然,實際上要交付程式時,並不是給一堆 .class 檔案,而是會將編譯好的 .class 檔包裝為一個J ava Archive File,也就是副檔名為 .jar 的檔案,在 JDK 的 bin 目錄下,附帶有一個 jar 工具程式,您可以直接執行 jar 程式,看看它的提示訊息: +當然,實際上要交付程式時,並不是給一堆 .class 檔案,而是會將編譯好的 .class 檔包裝為一個 Java Archive File,也就是副檔名為 .jar 的檔案,在 JDK 的 bin 目錄下,附帶有一個 jar 工具程式,您可以直接執行 jar 程式,看看它的提示訊息: ![執行 jar 工具程式](../images/img19-13.png) @@ -972,7 +972,7 @@ private void processTextArea() { 圖 19.14 準備製作 jar 檔案 -接著開啟文字模式,切換工作目錄至 jar 目錄下,然後鍵入以下的指令,表示將建立一個 JNotePad.jar 放到 bin 目錄中,來源是 classes 中的檔案,被放入的檔案將以 / 作為 .jar 檔案中的根目錄: +接著開啟文字模式,切換工作目錄至 jar 目錄下,然後鍵入以下的指令,表示將建立一個 JNotePad.jar 放到 bin 目錄中,來源是 classes 中的檔案,被放入的檔案將以 `/` 作為 .jar 檔案中的根目錄: ![製作 jar 檔案](../images/img19-15.png) @@ -985,7 +985,7 @@ private void processTextArea() { 接著您的文字編輯器就會啟動了,現在您不用將一堆 .class 檔案交付出去,只要交付這個 JNotePad.jar 就可以了。 -然而,真的要指定 Classpath 這麼麻煩嗎?其實還有更方便的做法,製作一 個Executable Jar 檔案,指定讀取 .jar 檔案時要執行的 Main-Class 就可以了,這需要準備一個 manifest.txt,當中寫下: +然而,真的要指定 Classpath 這麼麻煩嗎?其實還有更方便的做法,製作一個 Executable Jar 檔案,指定讀取 .jar 檔案時要執行的 Main-Class 就可以了,這需要準備一個 manifest.txt,當中寫下: ![準備 manifest 檔案](../images/img19-16.png) @@ -997,7 +997,7 @@ private void processTextArea() { 圖 19.17 指定 manifest 檔案並製作 jar 檔案 -在 .jar 檔案製作出來後,您可以在執行 java 時指定 -jar 引數,以及您的 .jar 檔案,java 程式會自動尋找 Main-Clas s並執行,例如下達以下的指令: +在 .jar 檔案製作出來後,您可以在執行 java 時指定 -jar 引數,以及您的 .jar 檔案,java 程式會自動尋找 Main-Class 並執行,例如下達以下的指令: java -jar bin/JNotePad.jar From bc7e4e1af04a6eb22c9d6cdab1b63765cd8ec104 Mon Sep 17 00:00:00 2001 From: SillyHP Date: Tue, 15 Sep 2020 14:59:57 +0800 Subject: [PATCH 19/24] Update CH12.md --- docs/CH12.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/CH12.md b/docs/CH12.md index 8dbf433..20d0787 100644 --- a/docs/CH12.md +++ b/docs/CH12.md @@ -198,8 +198,8 @@ public class GenericFoo2 { 您可以如下使用 GenericFoo2 類別,分別以 Integer 與 Boolean 設定 T1 與 T2 的真正型態: - GenericFoo foo = - new GenericFoo(); + GenericFoo2 foo = + new GenericFoo2(); 泛型可以用於宣告陣列型態,範例 12.7 是個簡單示範。 From fb6e1f1fed1385397ff5ece6b7c2bdf5c78d9c90 Mon Sep 17 00:00:00 2001 From: Justin Lin Date: Wed, 11 Nov 2020 14:57:58 +0800 Subject: [PATCH 20/24] errata --- docs/CH20.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CH20.md b/docs/CH20.md index e415d08..554279c 100644 --- a/docs/CH20.md +++ b/docs/CH20.md @@ -776,7 +776,7 @@ conn.rollback(savepoint); . . . conn.commit(); // 記得釋放save point -stmt.releaseSavepoint(savepoint); +conn.releaseSavepoint(savepoint); ``` > **良葛格的話匣子** 您的資料表格必須支援交易,才可以執行以上所提到的功能,例如在 MySQL 中可以建立 InnoDB 類型的表格: From ae9e3b5d26473c041c858d88491dbf38adf5f271 Mon Sep 17 00:00:00 2001 From: Justin Lin Date: Sun, 28 Aug 2022 22:11:54 +0800 Subject: [PATCH 21/24] update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 07c9a95..5a23400 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Java SE 6 技術手冊 原始碼範例都改為 UTF-8 編碼了,因此使用 `javac` 編譯時,記得加上 `-encoding UTF-8`。 -新的 Java 文件基於 JDK9 而撰寫,你可以在 [我的網站](https://openhome.cc) 上的 [Java Gossip](https://openhome.cc/Gossip/Java/) 進行閱讀。 +新的 Java 文件基於 JDK17 而撰寫,你可以在 [我的網站](https://openhome.cc) 上的 [Java Gossip](https://openhome.cc/zh-tw/java/) 進行閱讀。 ---------- From 4fbf0872ceb9a6a2ce8aa2c33ca5451cef95e343 Mon Sep 17 00:00:00 2001 From: Justin Lin Date: Sun, 28 Aug 2022 22:12:33 +0800 Subject: [PATCH 22/24] update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a23400..3c63b88 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Java SE 6 技術手冊 原始碼範例都改為 UTF-8 編碼了,因此使用 `javac` 編譯時,記得加上 `-encoding UTF-8`。 -新的 Java 文件基於 JDK17 而撰寫,你可以在 [我的網站](https://openhome.cc) 上的 [Java Gossip](https://openhome.cc/zh-tw/java/) 進行閱讀。 +新的 Java 文件基於 JDK17 而撰寫,你可以在 [我的網站](https://openhome.cc) 上的 [Java](https://openhome.cc/zh-tw/java/) 進行閱讀。 ---------- From ba6dac53aacb9f32e4df3d2d84520aab87c2b30e Mon Sep 17 00:00:00 2001 From: Justin Lin Date: Sun, 28 Aug 2022 22:14:48 +0800 Subject: [PATCH 23/24] update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c63b88..ea5f192 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Java SE 6 技術手冊 我在 GitBook 上用這本書前半本 [試排了一個版本](http://caterpillar.gitbooks.io/javase6tutorial/),如果你需要在 GitBook 上取得完整版本,請跟我聯絡! -《Java SE 6 技術手冊》(以及它先前的版本)是以 [我的網站](https://openhome.cc) 中早期學習 Java 的筆記 [JavaGossip1](https://openhome.cc/Gossip/JavaGossip-V1/) 與 [JavaGossip2](https://openhome.cc/Gossip/JavaGossip-V2/) 為基礎,記錄著我學習 Java 的一些心得。 +《Java SE 6 技術手冊》(以及它先前的版本)是以 [我的網站](https://openhome.cc) 中早期學習 Java 的筆記 JavaGossip1 與 JavaGossip2 為基礎,記錄著我學習 Java 的一些心得。 在 JDK7 問世之後,由於累積不少 Java 教學經驗與想法,為了有一本可以符合我教學所需的教材,因而在為 JDK7 撰寫 Java 書籍時,並不是改版《Java SE 6 技術手冊》,而是重新撰寫了一本 [《Java SE 7 技術手冊》](http://books.gotop.com.tw/bookdetails.aspx?bn=ACL034000)。 From c8518a42c95b8fb40b598fcfaaa489a464266878 Mon Sep 17 00:00:00 2001 From: Justin Lin Date: Sun, 28 Aug 2022 22:17:51 +0800 Subject: [PATCH 24/24] update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ea5f192..d166e19 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Java SE 6 技術手冊 《Java SE 6 技術手冊》(以及它先前的版本)是以 [我的網站](https://openhome.cc) 中早期學習 Java 的筆記 JavaGossip1 與 JavaGossip2 為基礎,記錄著我學習 Java 的一些心得。 -在 JDK7 問世之後,由於累積不少 Java 教學經驗與想法,為了有一本可以符合我教學所需的教材,因而在為 JDK7 撰寫 Java 書籍時,並不是改版《Java SE 6 技術手冊》,而是重新撰寫了一本 [《Java SE 7 技術手冊》](http://books.gotop.com.tw/bookdetails.aspx?bn=ACL034000)。 +在 JDK7 問世之後,由於累積不少 Java 教學經驗與想法,為了有一本可以符合我教學所需的教材,因而在為 JDK7 撰寫 Java 書籍時,並不是改版《Java SE 6 技術手冊》,而是重新撰寫了一本 [《Java SE 7 技術手冊》](https://play.google.com/store/books/details/%E6%9E%97%E4%BF%A1%E8%89%AF_Java_SE_7%E6%8A%80%E8%A1%93%E6%89%8B%E5%86%8A_%E9%9B%BB%E5%AD%90%E6%9B%B8?id=qscCBAAAQBAJ)。 《Java SE 6 技術手冊》呢?就我目前來看它,真的就像是筆記,然而就因為是筆記,想法、口吻、脈絡甚至範例上,都比較適合新手,在靜靜地留在我硬碟近兩年,我有一天看到它,想說放著也是沒用,不如開放它 ...