The Java Programming Language (Four Edition)
第一章 快速瀏覽
第二章 類與對象
第三章 類的擴展
第四章 接口
第五章 嵌套類和接口
第六章 枚舉類型
第七章 語言符號、值和變量
第八章 包裝器類
第九章 運算符和表達式
第十章 控制流
第十一章 泛型類型
第十二章 異常和斷言
第十三章 字符串與正則表達式
第十四章 線程
第十五章 注解
第十六章 反射
第十七章 垃圾回收器與內存
第十八章 包
第十九章 文檔注釋
第二十章 I/O 包
第二十一章 集合
第二十二章 各種常用工具
第二十三章 系統編程
第二十四章 國際化和本地化
第二十五章 標準包
第一章 快速瀏覽
第二章 類與對象
2.1、靜態字段
將字段聲明為 static(靜態字段),會使該字段只有一個實例,并且該實例能被該類的所有對象共享。
而且無論創建了該類的多少個實例,這個字段的都只有一份(內存中唯一?)。
2.2、初始化塊
字段另一種更復雜的初始化方式就是使用初始塊。
初始塊是一段出現在類聲明中的語句塊,它位于所有成員、構造器以及聲明之外,它可以初始化對象的字段。
它們會被優先執行,就像它們放置在類的每一個構造器的開頭那樣,如果有多個塊,它們會按照在類中出現的先后順序執行。
只有當類的所有構造器都聲明會拋出某個檢查型異常時,它的初始塊才可以拋出該異常。
應該審慎的使用初始塊,用它們來表示那些構造器不能單獨輕易完成的工作。
例如
public long idNum;
private static long nextID = 0;
{
idNum = nextID++;
}
2.3、靜態初始化
靜態初始塊被聲明為 static,只能引用類的靜態成員,不能拋出任何檢查型異常。
類內部的初始化順序是從前到后的,即代碼中的“字段初始化器”或“初始塊”都是按照從頭到尾的順序執行。
例如:要確保靜態字段 kk 在被訪問前已初始化。
static int kk = 9;
static{
System.out.println("1");
}
static{
System.out.println(kk);
}
2.4、參數值
準確的講,Java 只有一種參數傳遞方式,即值傳遞,這樣有利于保持簡單,傳遞的也只是這個值的副本。
2.5、使用方法來控制訪問
控制內部數據訪問的方法有時被稱為訪問方法(accessor method),使用它們可以增強類數據的封裝性。
第三章 類的擴展
3.1、擴展類的構造器
擴展類的構造器必須通過隱式或顯式地調用其超類的構造器,將繼承而來的字段的構造工作委托給超類。
構造器的順序依賴:
1、調用其超類的構造器(同樣 3步順序遞歸調用到 Object);
2、用這些字段的初始器和初始化塊來初始化它們;
3、執行構造體。
3.2、繼承與重定義成員
● 重載(overloading):提供多個具有相同名字的方法,但是它們擁有可以彼此區分開的不同簽名。
簽名是由方法名及其參數的類型和數量組成的,它并不包含返回類型或者拋出的異常列表,并且我們無法基于這些因素來重載方法。
不同重載的方法可以有不同類型的返回值。
● 重寫(overriding):將方法的超類實現替換為自己的實現。其簽名必須相同,但是他們的返回類型可以按照某種方式變換。
1、簽名(方法名、參數類型和個數)必須相同。
2、返回類型:引用類型的可以返回超類所聲明的子類(is a 關系),基本類型的返回必須相同。
3、訪問修飾符:可以改變,但只能提供更多的訪問權限,否則違反契約(不能替代超類實現)。
4、可以改變其他方法修飾符(synchronized、native和strictfp),static 則是必須保持一致,final 可以修飾重寫的方法(超類被重寫的方法則不能是 final)。
5、throws 子句:重寫 throws 子句可以少于超類所列出的數量、或者更為具體,還可以沒有任何 throws 子句。但是不能比超類的范圍廣(必須是多態兼容的)。
6、私有的方法:對于超類的 private 方法,子類沒有重寫,對私有方法的調用總會調用當前類中所聲明的方法實現。
例如:
public static void name() throws IndexOutOfBoundsException {....}
正確的重寫: public static void name() {....}
錯誤的重寫: public static void name() throws ClassNotFoundException {....}
3.3、兼容類型的實現
● 向上轉型:向繼承結構高端轉換,其線程是安全的。
● 向下轉型:向繼承結構低端轉換,非安全線程。
instanceof 操作符檢測一個對象所輸入的類,返回值為 false/true,常用語安全的將一個引用向下轉型。
例:if (sref instanceof More)
mref = (More) sref;
第四章 接口
4.1、抽象類與抽象方法
通過使用抽象類,我們可以聲明只定義了部分實現的類,而讓擴展類去提供其部分方法或者全部方法的具體實現。
任何擁有 abstract 方法的類都必須聲明為 abstract。
不能創建抽象類的對象,應為某些可能會被調用的方法沒有任何有效的實現。
不能是 static 因為 static 不能是 abstract 的。
4.2、接口
接口是純設計的表現形式,而類則是設計和實現的混合物。
接口類型的引用只能訪問接口成員。 Exam xxx = new ImplExam();
● 接口常量:隱式 public final static,必須有初始器(值)。
● 接口方法:隱式 public abstract,除注解外不允許有其他方法修飾符(如 synchronized、native和strictfp 等用于定義實現細節的修飾符);不能是 final 因為它還沒有被實現;不能是 static 因為 static 不能是 abstract 的。
4.3、擴展接口
可以使用 extends 擴展接口(接口繼承接口),接口支持多重繼承其他接口。
public interface C extends A, B {....}
● 繼承和隱藏常量
1、新聲明常量都將隱藏繼承而來的常量。
2、繼承而來的常量可以使用該常量完全限定名訪問(X.val,常見引用 static 成員形式)。
3、一個接口繼承了兩個或者多個名字相同常量,那么該常量所有簡單引用都具有二義性,會導致編譯出錯。所以,必須顯式使用接口常量,例如 X.val 和 Y.val 等等。
4、在繼承一個類的同時還實現了多個接口,也可能會遇到二義性的問題。
● 繼承、覆蓋和重載方法
1、一個接口同時實現了兩個簽名相同的方法,只會有一個這樣的方法存在,不會有二義性。
2、遇到簽名相同,返回不同的方法,除非某些返回的類型是其他的子類型,否則不同的返回會產生二義性。
4.4、接口的應用
任何一個希望被繼承的主要類,不管是否抽象類,都應該是一個接口的實現。(同樣是 is a 的關系,繼承只能擴展一個,但是接口能實現多個。)
第六章 枚舉類型
枚舉是一個特殊的類,它要表示的每一個具名常量都有與之對應的預定義實例。
第七章 語言符號、值和變量
第八章 包裝器類
8.1、包裝器類構造
每一個包裝器為它所指的基本類型定義一個不可改變對象。
例如: new Integer(1); 創建對象,他的值始終保持1,不可改變其值。
8.2、裝/拆箱轉換
Integer val = 3;
int x = val.intValue();
裝/拆箱轉換需分配一個包裝器類實例,這樣會消耗內存。
由于包裝器類是不可變的,所以兩個擁有相同值的對象在一定范圍是可以互換使用的(數值型為 -128~127)。
例如:
public static boolean sameArgs(Integer a, Integer b) {
return a == b; //判斷是否對象相同
}
true sameArgs(12, 12);
false sameArgs(12, new Integer(12));
false sameArgs(1280, 1280);
第九章 運算符和表達式
9.1、類型轉換
● 隱式拓寬:將整形轉換為浮點型,反之則不可以,整形轉換浮點型不會產生精度丟失現象。
長整型 long --> (隱式轉換)float --> (強制轉換)long 也是可行的,但會丟失精度。
● 顯式強制類型轉換
1、浮點數轉換為整數時,小數點后的部分會舍去。
2、double 強制轉換 float 可能會發生:a.精度丟失;b.得到0;c.或者大于 float 型范圍,得到無窮大。
3、整數間轉換,通過舍去高位,從而有可能被動改變符號。
9.2、運算符優先級
用括號將運算符括起來,可提高可讀性并確保正確的優先順序。
第十章 控制流
10.1、增強的 for 語句
for(Type loop-variable : set-expression)
statement
● 對于數組:使用 for-each 的優點在于不必使用數組下標,缺點是只能查看,不能修改數組元素。
● 對于元素集合:迭代的元素提供簡答語法結構,但不能同時迭代多個集合。
● 不是同步的,非線程安全的。
10.2、標號
label: statement
利用標號命名語句,在配合 break lable; 和 continue lable; 將控制流轉到嚴格受限的地方。
第十一章 泛型類型
第十二章 異常和斷言
12.1、斷言(assertion)
用來檢查永遠都應該是 true 的情況,如果發現斷言是 false,就會拋出異常。添加測試斷言可以為我們提供一種在程序中的錯誤引發奇怪后果前捕獲它們的途徑。
語法: assert eval-expr [: detail-expr]
在斷言被關閉時(默認情況下),斷言是不被計算了。所以 :
assert ++i < max; ++i 塊有可能不會起作用,建議分開寫。
斷言應該用來測試從來不發生的情況,因為斷言會拋出 Error 而不是 Exception。然而,使斷言成為必須會使代碼的運行環境變得復雜,因為當前斷言的打開及關閉間反復操作會帶來復雜性,所以不建議使用。
第十三章 字符串與正則表達式
13.1、正則表達式的匹配
java.util.regex 包提供 正則表達式(regular expression)用于“檢測字符串是否和某種模式匹配”或者“挑選字符串中各個部分”。
● 重用已編譯的模式:執行匹配所涉及的所有狀態都駐留在匹配器中,所以多個匹配器可以共享同一模式。
Pattern p = Pattern.compile(regularExpression); //將給定的正則表達式編譯到模式中
Matcher m = p.matcher(sequence); //利用輸入序列從模式創建匹配器
boolean b = m.matches(); //嘗試將整個輸入序列與該模式匹配
● 僅使用一次正則表達式
boolean b = Pattern.matches(regex, sequence); //編譯給定正則表達式并嘗試將給定輸入與其匹配
13.2、正則表達式的替換
通過調用模式的 matcher 方法從模式創建匹配器。創建匹配器后,可以使用它執行三種不同的匹配操作:
● matches 方法嘗試將整個輸入序列與該模式匹配。
● lookingAt 嘗試將輸入序列從頭開始與該模式匹配。
● find 方法掃描輸入序列以查找與該模式匹配的下一個子序列。
每個方法都返回一個表示成功或失敗的布爾值。通過查詢匹配器的狀態可以獲取關于成功匹配的更多信息。
ps.正則表達式本身復雜,只有在確實需要的情況下才使用它。在使用的時候,盡量確保模式的清晰度。
第十四章 線程
在計算機中每次執行一步的操作序列被稱為線程(thread),而這種單線程編程模型正是大多數程序員所使用的模型。線程可以獨立于其他線程執行一項任務,線程間也可以共享訪問對象。當兩個線程在修改同一塊數據時,如果它們是會對數據造成破壞的交叉方式去執行,那么就會出現競爭危機,解決的方法是利用一個鎖和對象關聯起來,這個鎖可以告知該對象是否正在被使用。
14.1、創建線程
● 擴展 Thread 類來創建新的線程,重寫 run 方法。
class PrimeThread extends Thread {
long minPrime;
PrimeThread(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
下列代碼會創建并啟動一個線程:
PrimeThread p = new PrimeThread(143); //創建該類實例
p.start(); //啟動線程,Java 虛擬機調用該線程的 run 方法。
● 聲明實現 Runnable 接口的類。該類然后實現 run 方法。
class PrimeRun implements Runnable {
long minPrime;
PrimeRun(long minPrime) {
this.minPrime = minPrime;
}
public void run() {
// compute primes larger than minPrime
. . .
}
}
下列代碼會創建并啟動一個線程:
PrimeRun p = new PrimeRun(143); //分配該類對象
new Thread(p).start(); //利用對象構造一個新的線程,并啟動
ps.每個線程都有一個標識名,多個線程可以同名。如果線程創建時沒有指定標識名,就會為其生成一個新名稱。
14.2、隱藏線程的 run 方法
run 方法是公共的,為了防止客戶端私自調用該方法,我們可以不起實現 Runable 接口,而是定義一個內部的 Runable 對象,確保不被濫用。例如:
public class Ping2 {
public Ping2() {
Runnable service = new Runnable(){
public void run() {
//......
}
} ;
new Thread(service).start();
}
}
14.3、線程的結束
有三種情況可使線程終止:
● run 方法正常返回(常規方式)
● run 方法意外結束
● 應用程序終止
Thread.currentThread().interrupt(); 向線程發送中斷:中斷一個線程通常不會影響它正在執行的操作,但是像 sleep 和 wait 這樣會拋出 InterruptedException 異常的方法除外。
一個線程可以使用某種形式的 join 方法來等待另一個線程終止。
不要使用 stop 方法:首先因為 stop 不能強制終止任何線程,無力對付惡意方法;其次,stop 會影響同步鎖,破壞對象。所以建議轉而使用 interrupt 方法。
14、4 同步
當多線程使用同一個對象時,存在著由于交叉操作而破壞數據的可能性,所以在某些動作操作對象之前,必須先獲得對象的鎖來阻止其他對象獲得這個鎖,直至它被持有者釋放為止。
利用 synchronized 的聲明,我們可以確保多個運行的線程不會互相干擾,因為每一個方法都將互斥地執行(在該方法調用結束前不能被其他方法調用)。
線程安全:多個線程可以并發調用對象上的方法,并且在每個線程中被調用的方法都在執行所期望的作業。
第十五章、注解
注解以結構化的方式提供了程序及其元素(類、方法、字段、變量等等)的信息,這些信息能夠被外部工具自動處理。
第十六章 反射
第十七章 垃圾回收器與內存
Java 虛擬機可以使用一種稱為垃圾回收(garbage collection)的技術來確定對象在程序中何時不再被引用,因此它可以安全地釋放對象占用的內存空間。
當我們從任何可執行代碼都無法到達某個對象時,它所占的空間就可以被回收。垃圾回收會占用一定的系統資源,通常情況下,只有需要更多的內存空間或者避免發生內存溢出時,垃圾回收器才會運行。但是程序可能沒有發生內存溢出,甚至在沒有接近內存退出的時候就退出了,所以可能根本不需要執行垃圾回收。
垃圾回收并不能保證內存中總是會有空間來創建新對象,不停的創建對象并置于使用列表中,就會造成內存泄漏。垃圾回收解決了很多(但并非全部)的內存分配問題。
System.runFinalization(); //運行掛起 finalization 的所有對象的終止方法
System.gc(); //運行垃圾回收器
Runtime.getRuntime().runFinalization();
Runtime.getRuntime().gc();
第十八章 包
18.1、導入機制
如果聲明了一個對 Xxx 類的引用,那么編譯器就會按照下面的順序搜索該類型:
1、包括繼承類型在內的當前類型。
2、當前類型的嵌套類型。
3、顯式命名的導入類型(單類型導入, import attr.Attributed;)
4、在同一個包中聲明的其他類型。
5、隱式命名的導入類型(按需導入,import attr.*;)
為了避免導入同名的兩個類型產生二義性,建議使用完全限定名。
第十九章 文檔注釋
19.1、剖析文檔注釋
/**
* 文檔注釋第一句應該是一個良好的摘要。
* 文檔注釋中可以嵌套標準的 HTML 標簽,用于格式指令或鏈接到其他文檔。
* 如果想使用 @ 字符,請使用 @,否則會被當作文檔注釋標簽的開始。
*/
第二十章 I/O 包
java.io 包是用流(stream)定義 I/O 的,流是有序的數據序列,它有一個源(輸入流)和目的地(輸出流)。
java.nio 包是用緩沖區(buffer)和通道(channel)定義 I/O 的,它用于高吞吐量服務器。
java.net 包基于對套接字的使用,用一種基于流或通道的模型提供對網絡 I/O 的特殊支持。
20.1、流的概述
I/O 主要有兩部分:
● 字符流(character stream,16位的 UTF-16 字符),它基于文本的 I/O,有讀取器(reader)和寫入器(write)。
● 字節流(byte stream,通常是 8位),它基于數據的 I/O,有輸入流(input stream)和輸出流(output stream)。
轉換流 InputStreamReader 與 OutputStreamWriter 可以通過指定或者默認的編碼機制在 字符流 與 字節流 之間互相轉換,類似于“黏合劑”,使我們可以以一種統一的、平臺無關的方式使用現有的 8位字符編碼機制去處理本地字符集。
InputStreamReader 對象讀取字節,并使用適合該流的編碼機制將其轉換為字符。
OutputStreamWriter 對象將接受提供的字符,使用適合的編碼機制將它們轉換為字節。
(注:無 ReaderStreamInput 類將字符轉換為字節,也無 WriterOutputStream 這個類將字節轉譯為字符)
InputStreamReader(InputStream in);
OutputStreamWriter(OutputStream out);
關閉轉換流的同時也會關閉掉將其關聯的字節流,所以一定要慎重。
20.2、數據字節流
通過流來傳輸特定類型的二進制數據。DataInput 和 DataOutput。
20.3、對象序列化
將對象的表示轉換為字節流的過程成為序列化,而從字節流中重構一個對象的過程被稱為反序列化。
當 ObjectOutputStream 寫入序列化對象是,該對象必須實現 Serializable 接口,聲明該類為可序列化的。
第二十一章 集合
21.1、迭代
對 Collection 使用 iterator 方法將獲得一個 Iterator 對象,這個對象可以遍歷集合內容,而且每次都只能訪問一個元素。
與增強型 for 循環相比,它可以通過 remove 方法移除元素,這種方式是安全的。
21.2、同步
java.util 包中提供的所有集合實現都是非同步的(除了 Vector、Dictionary、Hashtable 等遺留下來的集合)。
第二十二章 各種常用工具
● Formatter:用于產生格式化文本。
● Random:用以產生偽隨機數序列的類。
● Scanner:該類用于掃描文本,并根據正則表達式模式將其解析成基本數據類型或者字符串。
● Timer/TimerTask:用于調度將來某個時刻運行任務的一種方式(包括重復發生),每個 Timer 對象都有一個相關聯的線程。
第二十三章 系統編程
應用程序有時必須同 Java 虛擬機的運行時系統或底層操作系統進行交互。java.lang 中有三個主要的類提供了這個訪問:
23.1、System 類
System 類提供了用于操縱系統狀態的的靜態方法,并起到了資源倉庫的作用。它有四個通用領域的功能性:
● 標準 I/O 流
● 操縱系統屬性
● 用于訪問當前 Runtime 對象的工具方法和便利方法。
● 安全性
23.2、Runtime 類
提供了訪問虛擬機的運行時系統的接口。當前 Runtime 對象提供了對每個運行時系統的功能進行交互的能力,例如與垃圾回收器交互、執行其他程序及關閉運行時系統。
23.3、Process 類
表示的是正在運行的進程,它是通過調用 Runtime.exec 來執行另一個程序時創建的,也可以通過直接使用 ProcesssBuilder 對象來創建。
第二十四章 國際化和本地化
24.1、區域
java.util.Locale 對象描述了區域。
24.2、資源束
java.util.ResourceBundle 類。
24.3、貨幣
java.util.Currency 類可以幫助我們正確格式化貨幣值。
24.4、時間、日期、日歷
時間是用長整型 long 表示的,從 1970 年開始,可以通過 java.util.Date 類獲得時間,時間的比較可以用 before 和 after 方法,或者可以用 getTime/setTime 方法獲得/設置時間的 long 型值。Date 沒有提供本地化支持,我們可以使用更有效復雜的區域敏感的 Calendar 和 DateFormat 類來代替它。
抽象類 Calendar 表示不同標記時間的方式,同時也提供了許多用的日歷字段。
GregorianCalendar 類表示日歷。
SimpleDateFormat 類格式化、解析時間的類。
例:
Calendar cal = new GregorianCalendar(1972, Calendar.OCTOBER, 26);
System.out.println(cal.getTime());
第二十五章 標準包
● java.awt:抽象工具箱的抽象層,用來編寫平臺無關的圖形用戶界面。
● java.applet:Applet 類和相關類型,用于編寫可嵌入其他應用程序的子程序,如 HTML 瀏覽器。
● java.beans:用于編寫客戶端可重用的 JavaBeans 構件。
● java.lang.instrument:用于定義代理的服務。
● java.lang.managerment:用于監視并管理其所在的虛擬機以及操作系統服務。
● java.math:數學
● java.net:網絡
● java.rmi:遠程方法調用
● java.security 與相關的工具包:安全工具。
● java.sql:關系數據庫訪問
● javax.* :標準擴展工具包
● javax.sound:創建和操作聲音的子包。
● javax.swing:GUI構建的 Swing 包。
posted on 2008-10-11 23:28
黃小二 閱讀(340)
評論(0) 編輯 收藏 所屬分類:
J2SE