# 3.2 執行控制
(3)2 執行控制
Java使用了C的全部控制語句,所以假期您以前用C或C++編程,其中大多數都應是非常熟悉的。大多數程序化的編程語言都提供了某種形式的控制語句,這在語言間通常是共通的。在Java里,涉及的關鍵字包括`if-else`、`while`、`do-while`、`for`以及一個名為`switch`的選擇語句。然而,Java并不支持非常有害的`goto`(它仍是解決某些特殊問題的權宜之計)。仍然可以進行象`goto`那樣的跳轉,但比典型的`goto`要局限多了。
## 3.2.1 真和假
所有條件語句都利用條件表達式的真或假來決定執行流程。條件表達式的一個例子是`A==B`。它用條件運算符`==`來判斷`A`值是否等于`B`值。該表達式返回`true`或`false`。本章早些時候接觸到的所有關系運算符都可拿來構造一個條件語句。注意Java不允許我們將一個數字作為布爾值使用,即使它在C和C++里是允許的(真是非零,而假是零)。若想在一次布爾測試中使用一個非布爾值——比如在`if(a)`里,那么首先必須用一個條件表達式將其轉換成一個布爾值,例如`if(a!=0)`。
## 3.2.2 `if-else`
`if-else`語句或許是控制程序流程最基本的形式。其中的`else`是可選的,所以可按下述兩種形式來使用`if`:
```
if(布爾表達式)
語句
```
或者
```
if(布爾表達式)
語句
else
語句
```
條件必須產生一個布爾結果。“語句”要么是用分號結尾的一個簡單語句,要么是一個復合語句——封閉在括號內的一組簡單語句。在本書任何地方,只要提及“語句”這個詞,就有可能包括簡單或復合語句。
作為`if-else`的一個例子,下面這個`test()`方法可告訴我們猜測的一個數字位于目標數字之上、之下還是相等:
```
static int test(int testval) {
int result = 0;
if(testval > target)
result = -1;
else if(testval < target)
result = +1;
else
result = 0; // match
return result;
}
```
最好將流程控制語句縮進排列,使讀者能方便地看出起點與終點。
(1) `return`
`return`關鍵字有兩方面的用途:指定一個方法返回什么值(假設它沒有`void`返回值),并立即返回那個值。可據此改寫上面的`test()`方法,使其利用這些特點:
```
static int test2(int testval) {
if(testval > target)
return -1;
if(testval < target)
return +1;
return 0; // match
}
```
不必加上`else`,因為方法在遇到`return`后便不再繼續。
## 3.2.3 迭代
`while`,`do-while`和`for`控制著循環,有時將其劃分為“迭代語句”。除非用于控制迭代的布爾表達式得到“假”的結果,否則語句會重復執行下去。`while`循環的格式如下:
```
while(布爾表達式)
語句
```
在循環剛開始時,會計算一次“布爾表達式”的值。而對于后來每一次額外的循環,都會在開始前重新計算一次。
下面這個簡單的例子可產生隨機數,直到符合特定的條件為止:
```
//: WhileTest.java
// Demonstrates the while loop
public class WhileTest {
public static void main(String[] args) {
double r = 0;
while(r < 0.99d) {
r = Math.random();
System.out.println(r);
}
}
} ///:~
```
它用到了`Math`庫里的`static`(靜態)方法`random()`。該方法的作用是產生0和1之間(包括0,但不包括1)的一個`double`值。`while`的條件表達式意思是說:“一直循環下去,直到數字等于或大于0.99”。由于它的隨機性,每運行一次這個程序,都會獲得大小不同的數字列表。
## 3.2.4 `do-while`
`do-while`的格式如下:
```
do
語句
while(布爾表達式)
```
`while`和`do-while`唯一的區別就是`do-while`肯定會至少執行一次;也就是說,至少會將其中的語句“過一遍”——即便表達式第一次便計算為`false`。而在`while`循環結構中,若條件第一次就為`false`,那么其中的語句根本不會執行。在實際應用中,`while`比`do-while`更常用一些。
## 3.2.5 `for`
`for`循環在第一次迭代之前要進行初始化。隨后,它會進行條件測試,而且在每一次迭代的時候,進行某種形式的“步進”(Stepping)。`for`循環的形式如下:
```
for(初始表達式; 布爾表達式; 步進)
語句
```
無論初始表達式,布爾表達式,還是步進,都可以置空。每次迭代前,都要測試一下布爾表達式。若獲得的結果是`false`,就會繼續執行緊跟在`for`語句后面的那行代碼。在每次循環的末尾,會計算一次步進。
`for`循環通常用于執行“計數”任務:
```
//: ListCharacters.java
// Demonstrates "for" loop by listing
// all the ASCII characters.
public class ListCharacters {
public static void main(String[] args) {
for( char c = 0; c < 128; c++)
if (c != 26 ) // ANSI Clear screen
System.out.println(
"value: " + (int)c +
" character: " + c);
}
} ///:~
```
注意變量`c`是在需要用到它的時候定義的——在`for`循環的控制表達式內部,而非在由起始花括號標記的代碼塊的最開頭。`c`的作用域是由`for`控制的表達式。
以于象C這樣傳統的程序化語言,要求所有變量都在一個塊的開頭定義。所以在編譯器創建一個塊的時候,它可以為那些變量分配空間。而在Java和C++中,則可在整個塊的范圍內分散變量聲明,在真正需要的地方才加以定義。這樣便可形成更自然的編碼風格,也更易理解。
可在`for`語句里定義多個變量,但它們必須具有同樣的類型:
```
for(int i = 0, j = 1;
i < 10 && j != 11;
i++, j++)
/* body of for loop */;
```
其中,`for`語句內的`int`定義同時覆蓋了`i`和`j`。只有`for`循環才具備在控制表達式里定義變量的能力。對于其他任何條件或循環語句,都不可采用這種方法。
(1) 逗號運算符
早在第1章,我們已提到了逗號運算符——注意不是逗號分隔符;后者用于分隔函數的不同參數。Java里唯一用到逗號運算符的地方就是`for`循環的控制表達式。在控制表達式的初始化和步進控制部分,我們可使用一系列由逗號分隔的語句。而且那些語句均會獨立執行。前面的例子已運用了這種能力,下面則是另一個例子:
```
//: CommaOperator.java
public class CommaOperator {
public static void main(String[] args) {
for(int i = 1, j = i + 10; i < 5;
i++, j = i * 2) {
System.out.println("i= " + i + " j= " + j);
}
}
} ///:~
```
輸出如下:
```
i= 1 j= 11
i= 2 j= 4
i= 3 j= 6
i= 4 j= 8
```
大家可以看到,無論在初始化還是在步進部分,語句都是順序執行的。此外,盡管初始化部分可設置任意數量的定義,但都屬于同一類型。
## 3.2.6 中斷和繼續
在任何循環語句的主體部分,亦可用`break`和`continue`控制循環的流程。其中,`break`用于強行退出循環,不執行循環中剩余的語句。而`continue`則停止執行當前的迭代,然后退回循環起始和,開始新的迭代。
下面這個程序向大家展示了`break`和`continue`在`for`和`while`循環中的例子:
```
//: BreakAndContinue.java
// Demonstrates break and continue keywords
public class BreakAndContinue {
public static void main(String[] args) {
for(int i = 0; i < 100; i++) {
if(i == 74) break; // Out of for loop
if(i % 9 != 0) continue; // Next iteration
System.out.println(i);
}
int i = 0;
// An "infinite loop":
while(true) {
i++;
int j = i * 27;
if(j == 1269) break; // Out of loop
if(i % 10 != 0) continue; // Top of loop
System.out.println(i);
}
}
} ///:~
```
在這個`for`循環中,`i`的值永遠不會到達100。因為一旦`i`到達74,`break`語句就會中斷循環。通常,只有在不知道中斷條件何時滿足時,才需象這樣使用`break`。只要`i`不能被9整除,`continue`語句會使程序流程返回循環的最開頭執行(所以使`i`值遞增)。如果能夠整除,則將值顯示出來。
第二部分向大家揭示了一個“無限循環”的情況。然而,循環內部有一個`break`語句,可中止循環。除此以外,大家還會看到`continue`移回循環頂部,同時不完成剩余的內容(所以只有在i值能被9整除時才打印出值)。輸出結果如下:
```
0
9
18
27
36
45
54
63
72
10
20
30
40
```
之所以顯示0,是由于`0%9`等于0。
無限循環的第二種形式是`for(;;)`。編譯器將`while(true)`與`for(;;)`看作同一回事。所以具體選用哪個取決于自己的編程習慣。
(1) 臭名昭著的`goto`
`goto`關鍵字很早就在程序設計語言中出現。事實上,`goto`是匯編語言的程序控制結構的始祖:“若條件`A`,則跳到這里;否則跳到那里”。若閱讀由幾乎所有編譯器生成的匯編代碼,就會發現程序控制里包含了許多跳轉。然而,`goto`是在源碼的級別跳轉的,所以招致了不好的聲譽。若程序總是從一個地方跳到另一個地方,還有什么辦法能識別代碼的流程呢?隨著Edsger Dijkstra著名的“Goto有害”論的問世,`goto`便從此失寵。
事實上,真正的問題并不在于使用`goto`,而在于`goto`的濫用。而且在一些少見的情況下,`goto`是組織控制流程的最佳手段。
盡管`goto`仍是Java的一個保留字,但并未在語言中得到正式使用;Java沒有`goto`。然而,在`break`和`continue`這兩個關鍵字的身上,我們仍然能看出一些`goto`的影子。它并不屬于一次跳轉,而是中斷循環語句的一種方法。之所以把它們納入`goto`問題中一起討論,是由于它們使用了相同的機制:標簽。
“標簽”是后面跟一個冒號的標識符,就象下面這樣:
```
label1:
```
對Java來說,唯一用到標簽的地方是在循環語句之前。進一步說,它實際需要緊靠在循環語句的前方——在標簽和循環之間置入任何語句都是不明智的。而在循環之前設置標簽的唯一理由是:我們希望在其中嵌套另一個循環或者一個開關。這是由于`break`和`continue`關鍵字通常只中斷當前循環,但若隨同標簽使用,它們就會中斷到存在標簽的地方。如下所示:
```
label1:
外部循環{
內部循環{
//...
break; //1
//...
continue; //2
//...
continue label1; //3
//...
break label1; //4
}
}
```
在條件1中,`break`中斷內部循環,并在外部循環結束。在條件2中,`continue`移回內部循環的起始處。但在條件3中,`continue label1`卻同時中斷內部循環以及外部循環,并移至`label1`處。隨后,它實際是繼續循環,但卻從外部循環開始。在條件4中,break label1也會中斷所有循環,并回到label1處,但并不重新進入循環。也就是說,它實際是完全中止了兩個循環。
下面是`for`循環的一個例子:
```
//: LabeledFor.java
// Java’s "labeled for loop"
public class LabeledFor {
public static void main(String[] args) {
int i = 0;
outer: // Can't have statements here
for(; true ;) { // infinite loop
inner: // Can't have statements here
for(; i < 10; i++) {
prt("i = " + i);
if(i == 2) {
prt("continue");
continue;
}
if(i == 3) {
prt("break");
i++; // Otherwise i never
// gets incremented.
break;
}
if(i == 7) {
prt("continue outer");
i++; // Otherwise i never
// gets incremented.
continue outer;
}
if(i == 8) {
prt("break outer");
break outer;
}
for(int k = 0; k < 5; k++) {
if(k == 3) {
prt("continue inner");
continue inner;
}
}
}
}
// Can't break or continue
// to labels here
}
static void prt(String s) {
System.out.println(s);
}
} ///:~
```
這里用到了在其他例子中已經定義的`prt()`方法。
注意`break`會中斷`for`循環,而且在抵達`for`循環的末尾之前,遞增表達式不會執行。由于`break`跳過了遞增表達式,所以遞增會在`i==3`的情況下直接執行。在`i==7`的情況下,`continue outer`語句也會到達循環頂部,而且也會跳過遞增,所以它也是直接遞增的。
下面是輸出結果:
```
i = 0
continue inner
i = 1
continue inner
i = 2
continue
i = 3
break
i = 4
continue inner
i = 5
continue inner
i = 6
continue inner
i = 7
continue outer
i = 8
break outer
```
如果沒有`break outer`語句,就沒有辦法在一個內部循環里找到出外部循環的路徑。這是由于break本身只能中斷最內層的循環(對于`continue`同樣如此)。
當然,若想在中斷循環的同時退出方法,簡單地用一個`return`即可。
下面這個例子向大家展示了帶標簽的`break`以及`continue`語句在`while`循環中的用法:
```
//: LabeledWhile.java
// Java's "labeled while" loop
public class LabeledWhile {
public static void main(String[] args) {
int i = 0;
outer:
while(true) {
prt("Outer while loop");
while(true) {
i++;
prt("i = " + i);
if(i == 1) {
prt("continue");
continue;
}
if(i == 3) {
prt("continue outer");
continue outer;
}
if(i == 5) {
prt("break");
break;
}
if(i == 7) {
prt("break outer");
break outer;
}
}
}
}
static void prt(String s) {
System.out.println(s);
}
} ///:~
```
同樣的規則亦適用于`while`:
(1) 簡單的一個`continue`會退回最內層循環的開頭(頂部),并繼續執行。
(2) 帶有標簽的`continue`會到達標簽的位置,并重新進入緊接在那個標簽后面的循環。
(3) `break`會中斷當前循環,并移離當前標簽的末尾。
(4) 帶標簽的`break`會中斷當前循環,并移離由那個標簽指示的循環的末尾。
這個方法的輸出結果是一目了然的:
```
Outer while loop
i = 1
continue
i = 2
i = 3
continue outer
Outer while loop
i = 4
i = 5
break
Outer while loop
i = 6
i = 7
break outer
```
大家要記住的重點是:在Java里唯一需要用到標簽的地方就是擁有嵌套循環,而且想中斷或繼續多個嵌套級別的時候。
在Dijkstra的“Goto有害”論中,他最反對的就是標簽,而非`goto`。隨著標簽在一個程序里數量的增多,他發現產生錯誤的機會也越來越多。標簽和`goto`使我們難于對程序作靜態分析。這是由于它們在程序的執行流程中引入了許多“怪圈”。但幸運的是,Java標簽不會造成這方面的問題,因為它們的活動場所已被限死,不可通過特別的方式到處傳遞程序的控制權。由此也引出了一個有趣的問題:通過限制語句的能力,反而能使一項語言特性更加有用。
## 3.2.7 開關
“開關”(`Switch`)有時也被劃分為一種“選擇語句”。根據一個整數表達式的值,`switch`語句可從一系列代碼選出一段執行。它的格式如下:
```
switch(整數選擇因子) {
case 整數值1 : 語句; break;
case 整數值2 : 語句; break;
case 整數值3 : 語句; break;
case 整數值4 : 語句; break;
case 整數值5 : 語句; break;
//..
default:語句;
}
```
其中,“整數選擇因子”是一個特殊的表達式,能產生整數值。`switch`能將整數選擇因子的結果與每個整數值比較。若發現相符的,就執行對應的語句(簡單或復合語句)。若沒有發現相符的,就執行`default`語句。
在上面的定義中,大家會注意到每個`case`均以一個`break`結尾。這樣可使執行流程跳轉至`switch`主體的末尾。這是構建`switch`語句的一種傳統方式,但`break`是可選的。若省略`break`,會繼續執行后面的`case`語句的代碼,直到遇到一個`break`為止。盡管通常不想出現這種情況,但對有經驗的程序員來說,也許能夠善加利用。注意最后的`default`語句沒有`break`,因為執行流程已到了`break`的跳轉目的地。當然,如果考慮到編程風格方面的原因,完全可以在`default`語句的末尾放置一個`break`,盡管它并沒有任何實際的用處。
`switch`語句是實現多路選擇的一種易行方式(比如從一系列執行路徑中挑選一個)。但它要求使用一個選擇因子,并且必須是`int`或`char`那樣的整數值。例如,假若將一個字符串或者浮點數作為選擇因子使用,那么它們在`switch`語句里是不會工作的。對于非整數類型,則必須使用一系列`if`語句。
下面這個例子可隨機生成字母,并判斷它們是元音還是輔音字母:
```
//: VowelsAndConsonants.java
// Demonstrates the switch statement
public class VowelsAndConsonants {
public static void main(String[] args) {
for(int i = 0; i < 100; i++) {
char c = (char)(Math.random() * 26 + 'a');
System.out.print(c + ": ");
switch(c) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':
System.out.println("vowel");
break;
case 'y':
case 'w':
System.out.println(
"Sometimes a vowel");
break;
default:
System.out.println("consonant");
}
}
}
} ///:~
```
由于`Math.random()`會產生0到1之間的一個值,所以只需將其乘以想獲得的最大隨機數(對于英語字母,這個數字是26),再加上一個偏移量,得到最小的隨機數。
盡管我們在這兒表面上要處理的是字符,但`switch`語句實際使用的字符的整數值。在`case`語句中,用單引號封閉起來的字符也會產生整數值,以便我們進行比較。
請注意`case`語句相互間是如何聚合在一起的,它們依次排列,為一部分特定的代碼提供了多種匹配模式。也應注意將`break`語句置于一個特定`case`的末尾,否則控制流程會簡單地下移,并繼續判斷下一個條件是否相符。
(1) 具體的計算
應特別留意下面這個語句:
```
char c = (char)(Math.random() * 26 + 'a');
```
`Math.random()`會產生一個`double`值,所以26會轉換成`double`類型,以便執行乘法運算。這個運算也會產生一個`double`值。這意味著為了執行加法,必須無將`'a'`轉換成一個`double`。利用一個“轉換”,`double`結果會轉換回`char`。
我們的第一個問題是,轉換會對`char`作什么樣的處理呢?換言之,假設一個值是29.7,我們把它轉換成一個`char`,那么結果值到底是30還是29呢?答案可從下面這個例子中得到:
```
//: CastingNumbers.java
// What happens when you cast a float or double
// to an integral value?
public class CastingNumbers {
public static void main(String[] args) {
double
above = 0.7,
below = 0.4;
System.out.println("above: " + above);
System.out.println("below: " + below);
System.out.println(
"(int)above: " + (int)above);
System.out.println(
"(int)below: " + (int)below);
System.out.println(
"(char)('a' + above): " +
(char)('a' + above));
System.out.println(
"(char)('a' + below): " +
(char)('a' + below));
}
} ///:~
```
輸出結果如下:
```
above: 0.7
below: 0.4
(int)above: 0
(int)below: 0
(char)('a' + above): a
(char)('a' + below): a
```
所以答案就是:將一個`float`或`double`值轉換成整數值后,總是將小數部分“砍掉”,不作任何進位處理。
第二個問題與`Math.random()`有關。它會產生0和1之間的值,但是否包括值1呢?用正統的數學語言表達,它到底是`(0,1)`,`[0,1]`,`(0,1]`,還是`[0,1)`呢(方括號表示“包括”,圓括號表示“不包括”)?同樣地,一個示范程序向我們揭示了答案:
```
//: RandomBounds.java
// Does Math.random() produce 0.0 and 1.0?
public class RandomBounds {
static void usage() {
System.err.println("Usage: \n\t" +
"RandomBounds lower\n\t" +
"RandomBounds upper");
System.exit(1);
}
public static void main(String[] args) {
if(args.length != 1) usage();
if(args[0].equals("lower")) {
while(Math.random() != 0.0)
; // Keep trying
System.out.println("Produced 0.0!");
}
else if(args[0].equals("upper")) {
while(Math.random() != 1.0)
; // Keep trying
System.out.println("Produced 1.0!");
}
else
usage();
}
} ///:~
```
為運行這個程序,只需在命令行鍵入下述命令即可:
```
java RandomBounds lower
```
或
```
java RandomBounds upper
```
在這兩種情況下,我們都必須人工中斷程序,所以會發現`Math.random()`“似乎”永遠都不會產生0.0或1.0。但這只是一項實驗而已。若想到0和1之間有2的128次方不同的雙精度小數,所以如果全部產生這些數字,花費的時間會遠遠超過一個人的生命。當然,最后的結果是在`Math.random()`的輸出中包括了0.0。或者用數字語言表達,輸出值范圍是`[0,1)`。
- Java 編程思想
- 寫在前面的話
- 引言
- 第1章 對象入門
- 1.1 抽象的進步
- 1.2 對象的接口
- 1.3 實現方案的隱藏
- 1.4 方案的重復使用
- 1.5 繼承:重新使用接口
- 1.6 多態對象的互換使用
- 1.7 對象的創建和存在時間
- 1.8 異常控制:解決錯誤
- 1.9 多線程
- 1.10 永久性
- 1.11 Java和因特網
- 1.12 分析和設計
- 1.13 Java還是C++
- 第2章 一切都是對象
- 2.1 用引用操縱對象
- 2.2 所有對象都必須創建
- 2.3 絕對不要清除對象
- 2.4 新建數據類型:類
- 2.5 方法、參數和返回值
- 2.6 構建Java程序
- 2.7 我們的第一個Java程序
- 2.8 注釋和嵌入文檔
- 2.9 編碼樣式
- 2.10 總結
- 2.11 練習
- 第3章 控制程序流程
- 3.1 使用Java運算符
- 3.2 執行控制
- 3.3 總結
- 3.4 練習
- 第4章 初始化和清除
- 4.1 用構造器自動初始化
- 4.2 方法重載
- 4.3 清除:收尾和垃圾收集
- 4.4 成員初始化
- 4.5 數組初始化
- 4.6 總結
- 4.7 練習
- 第5章 隱藏實現過程
- 5.1 包:庫單元
- 5.2 Java訪問指示符
- 5.3 接口與實現
- 5.4 類訪問
- 5.5 總結
- 5.6 練習
- 第6章 類復用
- 6.1 組合的語法
- 6.2 繼承的語法
- 6.3 組合與繼承的結合
- 6.4 到底選擇組合還是繼承
- 6.5 protected
- 6.6 累積開發
- 6.7 向上轉換
- 6.8 final關鍵字
- 6.9 初始化和類裝載
- 6.10 總結
- 6.11 練習
- 第7章 多態性
- 7.1 向上轉換
- 7.2 深入理解
- 7.3 覆蓋與重載
- 7.4 抽象類和方法
- 7.5 接口
- 7.6 內部類
- 7.7 構造器和多態性
- 7.8 通過繼承進行設計
- 7.9 總結
- 7.10 練習
- 第8章 對象的容納
- 8.1 數組
- 8.2 集合
- 8.3 枚舉器(迭代器)
- 8.4 集合的類型
- 8.5 排序
- 8.6 通用集合庫
- 8.7 新集合
- 8.8 總結
- 8.9 練習
- 第9章 異常差錯控制
- 9.1 基本異常
- 9.2 異常的捕獲
- 9.3 標準Java異常
- 9.4 創建自己的異常
- 9.5 異常的限制
- 9.6 用finally清除
- 9.7 構造器
- 9.8 異常匹配
- 9.9 總結
- 9.10 練習
- 第10章 Java IO系統
- 10.1 輸入和輸出
- 10.2 增添屬性和有用的接口
- 10.3 本身的缺陷:RandomAccessFile
- 10.4 File類
- 10.5 IO流的典型應用
- 10.6 StreamTokenizer
- 10.7 Java 1.1的IO流
- 10.8 壓縮
- 10.9 對象序列化
- 10.10 總結
- 10.11 練習
- 第11章 運行期類型識別
- 11.1 對RTTI的需要
- 11.2 RTTI語法
- 11.3 反射:運行期類信息
- 11.4 總結
- 11.5 練習
- 第12章 傳遞和返回對象
- 12.1 傳遞引用
- 12.2 制作本地副本
- 12.3 克隆的控制
- 12.4 只讀類
- 12.5 總結
- 12.6 練習
- 第13章 創建窗口和程序片
- 13.1 為何要用AWT?
- 13.2 基本程序片
- 13.3 制作按鈕
- 13.4 捕獲事件
- 13.5 文本字段
- 13.6 文本區域
- 13.7 標簽
- 13.8 復選框
- 13.9 單選鈕
- 13.10 下拉列表
- 13.11 列表框
- 13.12 布局的控制
- 13.13 action的替代品
- 13.14 程序片的局限
- 13.15 視窗化應用
- 13.16 新型AWT
- 13.17 Java 1.1用戶接口API
- 13.18 可視編程和Beans
- 13.19 Swing入門
- 13.20 總結
- 13.21 練習
- 第14章 多線程
- 14.1 反應靈敏的用戶界面
- 14.2 共享有限的資源
- 14.3 堵塞
- 14.4 優先級
- 14.5 回顧runnable
- 14.6 總結
- 14.7 練習
- 第15章 網絡編程
- 15.1 機器的標識
- 15.2 套接字
- 15.3 服務多個客戶
- 15.4 數據報
- 15.5 一個Web應用
- 15.6 Java與CGI的溝通
- 15.7 用JDBC連接數據庫
- 15.8 遠程方法
- 15.9 總結
- 15.10 練習
- 第16章 設計模式
- 16.1 模式的概念
- 16.2 觀察器模式
- 16.3 模擬垃圾回收站
- 16.4 改進設計
- 16.5 抽象的應用
- 16.6 多重分發
- 16.7 訪問器模式
- 16.8 RTTI真的有害嗎
- 16.9 總結
- 16.10 練習
- 第17章 項目
- 17.1 文字處理
- 17.2 方法查找工具
- 17.3 復雜性理論
- 17.4 總結
- 17.5 練習
- 附錄A 使用非JAVA代碼
- 附錄B 對比C++和Java
- 附錄C Java編程規則
- 附錄D 性能
- 附錄E 關于垃圾收集的一些話
- 附錄F 推薦讀物