第 7 章

陣列( Array )
本投影片(下稱教用資源)僅授權給採用教用資源相關之旗標書籍為教科書之授課老師(下稱老師)專用,老
師為教學使用之目的,得摘錄、編輯、重製教用資源(但使用量不得超過各該教用資源內容之 80% )以製作為
輔助...
學習目標
 認識陣列
 學習陣列的宣告與配置
 瞭解多維陣列的結構與使用方法
 瞭解參照型別的特性
 活用陣列
前言
 假設您要撰寫一個程式 , 計算 5 個學生的國文成績
平均值 , 那麼這個程式可能會是這樣:
前言
 程式雖然很簡單 , 但是卻有幾個問題存在:
1. 因為有 5 個學生 , 所以在第 3 、 4 行宣告了 5 個
變數 , 分別用來記錄個別學生的成績。如果學生人數
變動的話 , 所需要宣告的變數數量就會變多 , 比如說
100 個學...
前言
 以上這些問題都會影響撰寫程式時的效率 , 也可能會
因為疏忽 , 造成程式的錯誤。
 舉例來說 , 很可能在 3 、 4 行的地方宣告了正確的
變數數目與名稱 , 但是在 5 、 6 行加總時漏了某個
變數;或者是在第 7 行計算平...
7-1 甚麼是陣列?
 要瞭解甚麼是陣列 , 可以先回頭看看保管箱的概念。
在之前的章節中 , 變數的使用都是只索取單一個保管
箱來存放一項資料 , 而這也正是前面提到計算平均成
績時招致各種問題的根本原因。
 我們所需要的是一種可以儲存多...
甚麼是陣列?
 陣列就是上述問題的解決方案。它相當於一次索取多
個相同大小的保管箱 , 就好像是一個由多個保管箱所
組成的組合櫃一樣。
 實際使用時 , 可以將組合櫃中個別的保管箱當成獨立
的變數 , 我們稱個別的保管箱為該陣列的一個元素
...
甚麼是陣列?
 更棒的是 , 我們隨時可以知道這個組合櫃中包含有幾
個保管箱 , 而且每個獨立的保管箱都會依照順序編上
序號 , 只要出示某個保管箱序號的號碼牌 , 就可以單
獨使用指定的保管箱 , 這個序號稱為是該保管箱的索
引碼 (Ind...
甚麼是陣列?

 接著就來實際撰寫使用陣列的程式。
7-1-1 陣列的宣告與配置
 要使用陣列 , 必須分成 2 個步驟 , 第 1 個步驟是宣
告陣列變數 , 第 2 個步驟是配置陣列。
 宣告陣列變數的目的就是索取一個保管箱 , 用來存放
指向組合櫃的號碼牌 , 而配置陣列的作用則是實際...
陣列的宣告與配置
陣列的宣告與配置
陣列變數的宣告
 在 ArrayAverage.java 的第 3 行就宣告了一個陣列
變數:
 只要在型別名稱的後面加上一對中括號 ([ ]), 就表示
要宣告一個指向可以放置該型別資料陣列的變數 , 也
就是說 , students 這...
陣列變數的宣告
 到這裡為止 , 只宣告了陣列變數本身 , 並沒有實際配
置儲存資料的空間 , 也沒有說明元素的個數。
 如果還是以保管箱來比擬的話 , 等於只索取了用來放
置組合櫃號碼牌的保管箱 , 還沒有取得組合櫃。因此
, 也還不能放...
陣列變數的宣告
 另外 , 從陣列的宣告方式也可以看出來 , 我們已經指
定了資料型別 , 所以 , 接下來索取到的組合櫃中 , 包
含的都是一樣大小的保管箱 , 只能放置相同型別的資
料。
 也就是說 , 您不能在同一個組合櫃的某個保管箱...
另 一種陣列變數的宣告方式
 宣告陣列的時候 , 您也可以將放在型別後面的那對中
括號放在變數的後面 , 變成這樣:
 不過我們並不建議您這樣做 , 因為寫成 double[ ] 時
, 可以直接讀成 double 陣列 , 清楚明白的表示...
陣列的配置
 宣告了陣列變數之後 , 接下來就可以配置陣列了。在
ArrayAverage.java 的第 4 行中 , 就是配置陣列的
動作:
 要配置陣列 , 必須使用 new 運算子。 new 運算子
的運算元就表示了所需要的空間大小...
陣列的配置
 換言之 , 執行過這一行後 , 就會配置一個組合櫃給
students, 其中擁有 5 個可以放置 double 型別資料
的保管箱。
陣列的配置
 配置好空間後 , 就可以將資料放入陣列中。
 要特別注意的是配置空間時並不一定要使用字面常數
來指定陣列的元素數量 , 如果在撰寫程式的當下還無
法決定陣列的大小 , 那麼也可以在程式實際執行的時
候 , 以變數 , 甚至於是...
陣列的使用
 配置好空間之後 , 程式在 5 ~ 9 行就將各個學生的
成績放入個別的元素中。
 指派的方式是在陣列變數的後面加上一對中括號 , 並
且在中括號內以數字來標示索引碼 , 指定要放入哪一
個元素中。
 要特別注意的是 , 第...
陣列的使用
 這樣一來 , 就記錄好各個學生的成績了。

 有了上面的內容之後 , 就可以用非常簡單的方式來計
算總和。
陣列的使用
 陣列本身除了可以放置資料外 , 還提供有許多項相關
於該陣列的資訊 , 稱為屬性 (Attributes) 。
 其中有一項屬性 , 名稱為 length, 可以告訴我們該陣
列中元素的數量。要取得這個屬性的內容 , 只要在陣...
陣列的使用
 這也就是 10 ~ 13 行所進行的工作:

 其中 , 第 11 行的 students.length 就是取得 students 所指陣
列的元素個數。
 在第 12 行中 , 就將每次迴圈所取出的元素加入 sum 變數...
陣列的使用
 最後 , 再利用陣列的 length 屬性值當除數 , 以算出
平均值:
 如此 , 就完成用陣列計算成績平均的程式。
超過陣列個數的存取
 在使用陣列時 , 必須小心不要使用超過陣列最後一個
元素的索引碼 , 舉例來說 , 以下這個程式就會發生錯
誤:
超過陣列個數的存取
 由於陣列元素的索引碼由 0 起算 , 因此在第 9 行想
要設定 a[4] 的內容時就會出錯。
 相同的道理 , 第 12 行中 , 迴圈結束的條件是 i <=
a.length, 所以當 i 為 4 的時候 , 迴圈...
超過陣列個數的存取
 對於還沒有習慣陣列的第 1 個元素索引碼為 0 的讀
者來說 , 這是很容易犯的錯 , 請特別留意。
▪ 請特別留意迴圈的索引碼控制 , 避免存取到不存在的
元素。
7-1-2 使用陣列的好處
 瞭解了陣列的使用方法後 , 就可以回過頭來看看 , 使
用陣列到底有甚麼好處?
 我們先比較看看 ArrayAverage.java 與
Average.java 這 2 個程式 , 從中發現
ArrayAve...
使用陣列的好處
▪ 只需宣告一個陣列變數 , 而不需要宣告和學生人數相
同數量的變數。
當然 , 在配置陣列空間的時候 , 還是得依據學生人數
指定大小 , 但至少程式的行數仍然維持不變。
更重要的是 , 假設學生的成績是從檔案中讀取 , 學生...
使用陣列的好處
▪ 指定陣列元素的內容時雖然看起來和使用變數時一樣
的累贅 , 不過如果資料是從檔案中循序讀入的話 , 就
可以使用索引碼依序放入陣列的元素中。此時 , 若是
使用多個變數的方式 , 就沒有辦法做到了。
▪ 可以使用索引碼存取陣...
使用陣列的好處
 從上述的說明應該可以瞭解 , 使用陣列已不單單是好
壞的問題 , 有些情況下 , 不使用陣列也就等於無法完
成任務 , 陣列反而是不可獲缺的要素了。
7-2 陣列的配置與初值 設定
 在上一節中 , 已經對於陣列的使用與優點有了基本的
認識。
 接下來 , 就要詳細解說陣列在宣告、配置、以及設定
陣列元素的內容時 , 各種可能的作法。
7-2-1 宣告同時配置
 雖然陣列在實際運作時會區分為宣告變數以及配置陣
列兩段工作 , 不過在撰寫程式時卻可以簡化 , 將宣告
以及配置的動作合在同一個指定運算式中。
 寫法很簡單 , 就是將原本宣告的敘述和配置空間的
new 運算子透...
宣告同時配置

 程式的執行結果完全和之前的程式一樣。
宣告同時配置
 前面曾經提過 , 配置陣列時 , 並不是只能用字面常數
來指定元素的個數 , 也可以使用變數或是運算式 , 例
如:

 由於元素個數必須為整數 , 因此只有運算結果為整數
值 的運算式才能用來指定陣列的元素個數。
7-2-2 設定陣列的初值
 如果您的陣列是在撰寫程式的當時就已經知道個別元
素的初值 , 那麼您還可以再把計算平均成績的程式簡
化 , 在宣告的同時 , 直接列出個別元素的初值 , 替代
配置元素以及設定個別元素的動作 , 例如。
設定陣列的初值
設定陣列的初值
1. 要直接設定陣列的初值 , 必須使用一對大括號 , 列
出陣列中每一個元素的初值。
2. 記得要在右大括號後面加上分號 (;), 表示整個宣告
敘述的結束。
 實際上這段程式在執行時的運作方式 , 和原來的程
式是一模一樣...
設定陣列的初值

▪ 在宣告同時設定元素初值時 , 別忘了最後面大括號後
的分號 , 這是撰寫程式時很容易疏忽的地方。
7-2-3 配合陣列使用迴圈
 從本章一開始的範例到目前為止 , 您可能已經發現我
們經常會使用迴圈來依序處理陣列中的個別元素。
 舉例來說 , 在 ArrayAverage.java 中計算平均成績
時 , 就使用了迴圈依序取出個別學生的...
配合陣列使用迴圈
 要進行這些工作 , 就必須自行撰寫迴圈 , 並且宣告迴
圈變數 , 然後透過迴圈變數做為索引碼 , 取出指定元
素的值。
 為了避免這樣的麻煩 , Java 提供了另外一種 for 迴
圈的語法 ( 稱為 for-eac...
配合陣列使用迴圈
配合陣列使用迴圈
1. for(:) 的作用 , 就是迴圈進行時 , 每一輪就從 ":"
後面所列的陣列取出下一個元素 , 放到冒號前面所
指定的變數中 , 然後執行迴圈本體的敘述。
2. ":" 前面的變數必須和陣列的型別一致 , 否則編譯時...
配合陣列使用迴圈
 如果拆解開來 , 這個程式的第 5 ~ 7 行就相當於以
下這樣:

 for-each 迴圈可以幫助我們撰寫出簡潔的迴圈敘述 ,
除了陣列外 , 在第 17 章介紹集合物件的時候 , 還會
看到它的用處。
foreach 迴圈的注意事項
 foreach 迴圈雖然好用 , 不過有 3 點需要注意:
▪ 實際上編譯器會把 foreach 迴圈拆解為一般的 for 迴圈 ,
就像剛剛所展示的一樣。因此 , 使用 foreach 迴圈除了在
撰寫程式...
7-3 多維陣列 (Multi-Dimensional Array)
 由於陣列的每一個元素都可以看做是單獨的變數 , 如果
每一個元素自己本身也指向一個陣列 , 就會形成一個指
向陣列的陣列。
 這種陣列 , 稱為 2 維陣列 (2 - ...
7-3-1 多維陣列的宣告
 要宣告多維陣列 , 其實和宣告 1 維陣列沒有太大的
差別 , 只要將 1 維陣列的觀念延伸即可。
 舉例來說 , 要宣告一個所有元素都是指向 int 陣列的
陣列時 , 由於陣列中每一個元素都指向一個 int...
多維陣列的宣告
 如果依循前面對於 1 維陣列宣告時的瞭解 , 可以把
int[ ] 當成是一種新的資料型別 , 表示一個用來儲存
int 型別資料的陣列。這樣一來 , 上述的宣告就可以
解讀為:
 表示 a 是一個陣列 , 它的每一個元素...
多維陣列的宣告
 相同的道理,如果要宣告一個 3 維陣列,可以這樣
宣告:
 我們可以解讀成 b 是一個陣列 , 它的每一個元素都
指向 int[ ][ ] 型別的資料 , 也就是一個 2 維的 int
陣列。如果套用組合櫃的觀念 , 這等...
7-3-2 多維陣列的配置
 多維陣列的配置和 1 維陣列相似 , 只要使用 new
運算子 , 再指定各層的元素數量即可。例如:
多維陣列的配置
1. 第 4 行就是實際配置 2 維陣列的空間 , 這就等於
是先配置一個擁有 3 個元素的陣列 , 其中每一個元
素各指向一個擁有 4 個 int 型別資料的陣列。
2. 由於 a 是指向一個擁有 3 個元素的陣列 , 所以
...
多維陣列的配置
分層配置
 由於 a 是指向一個有 3 個元素的陣列 , 而每個元素
各自指向一個陣列 , 因此上述的程式也可以改寫成這
樣:
分層配置

1. 第 4 行的意思就是先配置一個有 3 個元素的陣列 , 其
中每一個元素都是指向一個可以存放 int 型別資料的陣
列 , 這時尚未配置第 2 維的陣列。
2. 第 6 ~ 8 行就透過迴圈 , 幫剛剛配置的陣列中的每一個
元...
分層配置
 如果您使用這種配置方式 , 請特別注意只有右邊維度
的元素數目可以留空 , 最左邊的維度一定要指明。也
就是說 , 您不能撰寫以下這樣的程式:
分層配置
 但這樣就是可以的:
非矩形的多維陣列
 由於 Java 是以剛剛所說明的方式配置多維陣列 , 因
此我們甚至於還可以建立一個奇特的多維陣列 , 例如
:
非矩形的多維陣列
非矩形的多維陣列
1. 第 3 行宣告 a 指向一個擁有 3 個元素的陣列 ,
每個元素都指向 1 個可以放置 int 型別資料的陣列
。
2. 第 5 ~ 7 行 , 分別為 a[0] 、 a[1] 、與 a[2] 配置了
不同大小的陣列。
...
非矩形的多維陣列
非矩形的多維陣列
▪ 由於多維度陣列只是陣列的陣列 , 所以可以有非矩形
的陣列 , 這是 Java 比較特別的地方 , 請多留意其結
構與原理。
直接配置與設定多維陣列
 多維陣列也和 1 維陣列一樣 , 可以同時配置並且設
定個別元素的內容。
 只要使用多層的大括號 , 就可以對應到多維陣列的各
個維度 , 直接指定要配置的元素個數與元素內容 , 例
如。
直接配置與設定多維陣列
直接配置與設定多維陣列
 在第 4 行中 , 就等於是宣告了
陣列變數 a, 指向一個 2 維陣
列 , 其中每個元素都指向一個擁
有 4 個整數的陣列 , 同時還設
定了個別元素的內容。
多維陣列的使用
 多維陣列的使用也和 1 維陣列一樣 , 只要在各維度
指定索引碼 , 就可以將指定的元素取出。
 舉例來說 , a[2][3] 就是將 a 指向的多維陣列中第 3
排的組合櫃中的第 4 個保管箱的內容取出來。
 如果是 ...
多維陣列的使用
多維陣列的使用
1. 第 5 行 , 由於 a 指向一個 2 維陣列 , 因此這個
for-each 迴圈取出的元素是 int[ ] 型別。
2. 第 6 行 , 第 2 層的 for-each 迴圈取出來的才是
真正的資料。
7-4 參照型別 (Reference Data Type)
 在第 3 章曾經提過 , 陣列是屬於參照型別的資料 ,
不過在當時因為還沒有實際介紹參照型別 , 因此對於
參照型別 , 並沒有著墨太多。
 在這一小節中 , 就要詳細探討參照...
7-4-1 參照型別的特色
 我們以底下這個陣列為例來說明參照型別的特性:
間接存取資料
 參照型別的第一個特性是間接存取資料 , 而不是直
接使用變數的內容。舉例來說 , 當執行以下這行程
式時:
 實際上進行的動作如下:
1. 先把變數 a 的內容取出來 , 得到號碼牌 15 。
2. 到編號 15 的組合櫃中...
間接存取資料
間接存取資料
 也就是因為在存取資料時 , 實際上是參照變數所記錄
的位址 ( 號碼牌 ) 去存取真正的資料 , 因此才稱之為
是參照型別。
 由於必須透過間接的方式存取資料 , 因此存取的時間
一定會比使用直接存取資料的基本型別要久。
...
指定運算不會複製資料
 先來看看以下這個程式:
指定運算不會複製資料
指定運算不會複製資料
 a 和 b 的元素竟然一模一樣?
 如果依照之前對於基本型別資料的觀念 , 那麼對於執
行的結果可能就會覺得奇怪。
 陣列 a 不是應該是 20 、 30 、 40, 而陣列 b 應
該是 20 、 30 、 10...
指定運算不會複製資料
 其實這正是參照型別最特別但也最需要注意的地方。
 由於參照型別的變數所儲存的是存放真正資料的組合
櫃的號碼牌 , 因此在第 5 行的指定運算中 , 等於是
把變數 a 所儲存的號碼牌複製一個放到變數 b 中 ,
而不...
指定運算不會複製資料
指定運算不會複製資料
 因此 , 接下來透過 b 對陣列的操作 , 就等於是對 a
所指陣列的操作 , 而現在 a 和 b 根本就是指向同一
個陣列 , 所以更改的是同一個陣列。
▪ 請確實瞭解此一特性 , 這是考題中常見的陷阱。
指定運算不會複製資料
 事實上 , 對於一個陣列變數來說 , 也可以隨時變換整
個陣列 , 例如:
指定運算不會複製資料
指定運算不會複製資料
 其中第 11 ~ 13 行就重新幫 a 配置陣列。
 這個新的陣列和一開始所配置的陣列大小也不一樣 ,
完全是新的陣列 , 也就是捨棄了原本的陣列 , 再配置
一個新的陣列給 a 。
7-4-2 匿名陣列 (Anonymous Array)
 前面介紹的 {1,2,3...} 語法 , 只能用在宣告陣列時做
為初始化之用。
 如果要用在其他地方 , 例如重新配置陣列 , 則此語法
也可用來動態建立陣列 , 但必須在大括號...
匿名陣列 (Anonymous Array)
 另外有一點請注意 , 在宣告陣列時若有初始化 , 那麼
就不可在 [ ] 中指定數目。例如底下的程式:

 上面程式的最後一行是正確的 , 但並未指定初值 , 此
時數值型別的元素預設為 0,...
重新配置陣列的注意事項
 在重新配置陣列的時候 , 有一點要注意:重新配置時
可以先用 a = new int[2]; 來配置陣列元素 , 然後再
個別指定元素的值 ( 例如 a[0]=100;) ;或是也可使
用前面介紹過的匿名陣列 (a ...
7-4-3 資源回收系統 (Garbage Collection
System)
 瞭解了上述參照型別的特色之後 , 您可能已經想到了
一個問題 , 如果不斷的配置陣列 , 也就是不斷的索取
組合櫃 , 會不會有組合櫃全部被佔用 , 沒有閒置...
參照計數 (Reference Count)
 為了讓資源回收系統能夠運作 , 就必須要有一套監控
組合櫃使用狀況的機制 , 這樣才能在發現有閒置的組
合櫃時 , 自動將之回收。
 Java 的作法很簡單 , 它會監控對應於每一個組合櫃
的...
參照計數 (Reference Count)
 當程式執行完第 5 行後 , 變數 a 和 b 都擁有對應
同一個陣列的號碼牌 , 也就是該陣列目前已經發出了
2 個號碼牌。
 這個數目稱為參照計數 (Reference Count), 因...
參照計數 (Reference Count)
 那麼參照計數在甚麼狀況下才會減少呢?這可以分成
3 種狀況:
▪ 參照型別的變數自行歸還號碼牌:只要將參照型別的
變數指定為字面常數 null, 亦即:

就等於是告訴資源回收系統該變數不再需要...
參照計數 (Reference Count)
▪ 讓變數參照到其他組合櫃:參照型別變數只能握有一
個號碼牌 , 如果指派給它另一個組合櫃的號碼牌 , 像
是重新配置陣列 , 它就必須歸還原本的號碼牌 , 因此
對應組合櫃的參照計數也會減 1 。...
參照計數 (Reference Count)
 有了這樣的規則 , 資源回收系統就可以知道哪些組合
櫃還可能會再用到 , 而哪一些組合櫃不可能會再用到
了。
回收的時機
 一旦發現有閒置的組合櫃之後 , 資源回收系統並不會
立即進行回收的動作 , 而是先將這個組合櫃的號碼記
錄下來。
 這是因為回收組合櫃的工作並不單單只是將其收回 ,
可能還必須將組合櫃拆開 , 或是與其他的組合櫃集中
放置等搬...
回收的時機
 因此 , 資源回收系統會先將要回收的組合櫃記錄下來
, 等到發現程式似乎沒有在執行繁重的工作 , 像是等
待網路連線的回應時 , 才進行回收的工作。
 透過這樣的方式 , 資源回收系統不但可以自動幫您將
閒置的資源回收 , 而...
7-5 命令列參數: argv 陣列
 雖然到了這一章才介紹陣列 , 但事實上之前所展示過
的每一個程式 , 都已經使用過陣列了。
 如果您眼尖的話 , 一定會注意到每個程式 main( ) 方
法的小括號中 , 都有 String[ ] ...
7-5-1 argv 與 main() 方法
 在第 2 章曾經說過 , main( ) 方法是 Java 程式的起
點 , 當我們在命令提示符號下鍵入指令要求執行
Java 程式時 , 例如:
 Java 虛擬機器就會載入 ShowArg...
argv 與 main() 方法
 這樣一來 , Java 虛擬機器就會配置一個字串陣列 ,
然後將程式名稱 ( 以此例來說就是 ShowArgv) 之後
的字串 , 以空白字元分隔切開成多個單字 ( 以此例來
說 , 就有 2 個單字 , ...
argv 與 main() 方法
 請看底下這個程式:

 程式中第 3 、 4 行就使用了一個 for 迴圈 , 將
argv 所指向的字串陣列的元素依序顯示出來。
argv 與 main() 方法
 如果您使用以下指令執行這個程式:
 執行的結果就會顯示:
argv 與 main() 方法
 如果您要傳遞的資訊本身包含有空白 , 可以使用一對
雙引號 (") 將整串字括起來 , 例如:
 其中的 this is a text 會被拆解為 4 個單字,如下:
argv 與 main() 方法
 如果 "this is a text" 是單一項資訊 , 就得使用一對雙
引號括起來:
 執行結果如下:

 其中 "this is a text" 就被當作是一項資訊 , 而不會被
拆成 this 、...
7-5-2 argv 陣列內 容的處理
 由於 argv 指向的是一個字串陣列 , 因此不論在指令
行中輸入甚麼資訊 , 實際上在 argv 中都只是一串文
字。
 如果您希望傳遞的是數值資料 , 那麼就必須自行將由
數字構成的字串轉換成為...
argv 陣列內 容的處理
 要得到 5 * 4 * 3 * 2 * 1 的值 , 那麼就必須將傳入的
字串 "5" 轉換成整數才行:
argv 陣列內 容的處理
▪

執行以上範例程式時 , 若未在程式名稱後面加上數值
、或故意加上非數字的參數 , 則執行時會發生錯誤 ,
稱為『 例外』 , 解決例外的方式會在第 14 章說明
。

1. 第 5 行就是將字串轉換成整數 , ...
 7-A 將陣列運用在查表上
 7-B 搜尋 (Search) 資料
 7-C 找出最大與最小值
 7-D 排序(Sorting)
1. Which statement s will legally declare and initialize an
array?
A. int [ ] a = {"1","2","3"} ;
B. int [ ] a = {1,2,3} ;...
2. Please drag and drop the appropriate code into the
following empty boxes:

Code:
3. Given:

Place the appropriate result to the end of the following two
command line executions:
java ArgShow Place result...
Result
4. Given:

Which, inserted at line 4, will compile? (choose three or
four)
A. char a; for(int i=0; i<b.length; i++) { a = ...
5. Given:

Which statements are true? (Choose all that apply. )
A. Compiles error at L1.
B. Compiles error at L2.
C. Compi...
6. Given:
Which statements are true? (Choose a l l that apply. )
A. the array referenced by b is eligible for garbage
collection at ...
7. Given:

Which statement is true?
A. This program will not compile.
B. Runtime error at line 5.
C. Runtime error at line...
8. Which are legal declarations? (Choose all that apply)
A. int[] a = new int[3];
B. int b[3];
C. int c[] = new int[] {1,2...
SCJP ch07
SCJP ch07
SCJP ch07
Upcoming SlideShare
Loading in …5
×

SCJP ch07

222 views

Published on

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
222
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
11
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

SCJP ch07

  1. 1. 第 7 章 陣列( Array ) 本投影片(下稱教用資源)僅授權給採用教用資源相關之旗標書籍為教科書之授課老師(下稱老師)專用,老 師為教學使用之目的,得摘錄、編輯、重製教用資源(但使用量不得超過各該教用資源內容之 80% )以製作為 輔助教學之教學投影片,並於授課時搭配旗標書籍公開播放,但不得為網際網路公開傳輸之遠距教學、網路教 學等之使用;除此之外,老師不得再授權予任何第三人使用,並不得將依此授權所製作之教學投影片之相關著 作物移作他用。 著作權所有 © 旗標出版股份有限公司
  2. 2. 學習目標  認識陣列  學習陣列的宣告與配置  瞭解多維陣列的結構與使用方法  瞭解參照型別的特性  活用陣列
  3. 3. 前言  假設您要撰寫一個程式 , 計算 5 個學生的國文成績 平均值 , 那麼這個程式可能會是這樣:
  4. 4. 前言  程式雖然很簡單 , 但是卻有幾個問題存在: 1. 因為有 5 個學生 , 所以在第 3 、 4 行宣告了 5 個 變數 , 分別用來記錄個別學生的成績。如果學生人數 變動的話 , 所需要宣告的變數數量就會變多 , 比如說 100 個學生 , 那麼就得宣告 100 個變數。不但程式 寫起來很長 , 光是要寫上 100 個變數的名稱 , 就很 容易寫錯。 2. 相同的問題也會出現在第 5 、 6 行加總學生成績的 地方。 3. 最後 , 在第 7 行計算平均成績的時候 , 也會因為學 生人數的變動 , 而必須自行修改除數。
  5. 5. 前言  以上這些問題都會影響撰寫程式時的效率 , 也可能會 因為疏忽 , 造成程式的錯誤。  舉例來說 , 很可能在 3 、 4 行的地方宣告了正確的 變數數目與名稱 , 但是在 5 、 6 行加總時漏了某個 變數;或者是在第 7 行計算平均時除錯了人數。  如果能夠有一種比較好的資料紀錄與處理方式 , 幫助 我們解決以上的問題 , 就可以避免許多不必要的錯誤 發生了。在這一章中 , 就要介紹可以解決上述問題的 新資料型別 -- 陣列。
  6. 6. 7-1 甚麼是陣列?  要瞭解甚麼是陣列 , 可以先回頭看看保管箱的概念。 在之前的章節中 , 變數的使用都是只索取單一個保管 箱來存放一項資料 , 而這也正是前面提到計算平均成 績時招致各種問題的根本原因。  我們所需要的是一種可以儲存多項資料的變數 , 而且 可以隨時知道所儲存資料的數量 , 同時還能依據數量 , 一一取出各項資料進行處理。
  7. 7. 甚麼是陣列?  陣列就是上述問題的解決方案。它相當於一次索取多 個相同大小的保管箱 , 就好像是一個由多個保管箱所 組成的組合櫃一樣。  實際使用時 , 可以將組合櫃中個別的保管箱當成獨立 的變數 , 我們稱個別的保管箱為該陣列的一個元素 (Element ) 。
  8. 8. 甚麼是陣列?  更棒的是 , 我們隨時可以知道這個組合櫃中包含有幾 個保管箱 , 而且每個獨立的保管箱都會依照順序編上 序號 , 只要出示某個保管箱序號的號碼牌 , 就可以單 獨使用指定的保管箱 , 這個序號稱為是該保管箱的索 引碼 (Index Number) 。  有了這樣的組合櫃之後 , 原本計算平均成績的程式 , 就可以用以下的演算法來撰寫了。
  9. 9. 甚麼是陣列?  接著就來實際撰寫使用陣列的程式。
  10. 10. 7-1-1 陣列的宣告與配置  要使用陣列 , 必須分成 2 個步驟 , 第 1 個步驟是宣 告陣列變數 , 第 2 個步驟是配置陣列。  宣告陣列變數的目的就是索取一個保管箱 , 用來存放 指向組合櫃的號碼牌 , 而配置陣列的作用則是實際索 取組合櫃 , 並且把組合櫃的號碼牌放入陣列變數中 , 我們來看看實際的程式。
  11. 11. 陣列的宣告與配置
  12. 12. 陣列的宣告與配置
  13. 13. 陣列變數的宣告  在 ArrayAverage.java 的第 3 行就宣告了一個陣列 變數:  只要在型別名稱的後面加上一對中括號 ([ ]), 就表示 要宣告一個指向可以放置該型別資料陣列的變數 , 也 就是說 , students 這個變數會指到一個儲存 double 資料的陣列。
  14. 14. 陣列變數的宣告  到這裡為止 , 只宣告了陣列變數本身 , 並沒有實際配 置儲存資料的空間 , 也沒有說明元素的個數。  如果還是以保管箱來比擬的話 , 等於只索取了用來放 置組合櫃號碼牌的保管箱 , 還沒有取得組合櫃。因此 , 也還不能放入資料。
  15. 15. 陣列變數的宣告  另外 , 從陣列的宣告方式也可以看出來 , 我們已經指 定了資料型別 , 所以 , 接下來索取到的組合櫃中 , 包 含的都是一樣大小的保管箱 , 只能放置相同型別的資 料。  也就是說 , 您不能在同一個組合櫃的某個保管箱中放 int 型別的資料 , 而在另一個保管箱中放 double 型 別的資料。
  16. 16. 另 一種陣列變數的宣告方式  宣告陣列的時候 , 您也可以將放在型別後面的那對中 括號放在變數的後面 , 變成這樣:  不過我們並不建議您這樣做 , 因為寫成 double[ ] 時 , 可以直接讀成 double 陣列 , 清楚明白的表示出該 變數會指向一個 double 型別的陣列 , 同時也可以將 double[ ] 當成是一種資料型別。  在本書的程式中 , 都會使用此種方式宣告陣列。 ▪ 不論是將中括號置於型別名稱之後還是變數名稱之後 , 都是合法的方式 , 請切記。
  17. 17. 陣列的配置  宣告了陣列變數之後 , 接下來就可以配置陣列了。在 ArrayAverage.java 的第 4 行中 , 就是配置陣列的 動作:  要配置陣列 , 必須使用 new 運算子。 new 運算子 的運算元就表示了所需要的空間大小。  以本例來說 , 中括號裡頭的數字 5 就表示需要 5 個 保管箱 , 而中括號前面的 double 就表示了這 5 個 保管箱都要用來放置 double 型別的資料。
  18. 18. 陣列的配置  換言之 , 執行過這一行後 , 就會配置一個組合櫃給 students, 其中擁有 5 個可以放置 double 型別資料 的保管箱。
  19. 19. 陣列的配置  配置好空間後 , 就可以將資料放入陣列中。  要特別注意的是配置空間時並不一定要使用字面常數 來指定陣列的元素數量 , 如果在撰寫程式的當下還無 法決定陣列的大小 , 那麼也可以在程式實際執行的時 候 , 以變數 , 甚至於是運算式來指定要配置的元素個 數。 ▪ 對於熟悉其他程式語言的讀者 , 要特別留意 Java 的 陣列需要配置這件事。
  20. 20. 陣列的使用  配置好空間之後 , 程式在 5 ~ 9 行就將各個學生的 成績放入個別的元素中。  指派的方式是在陣列變數的後面加上一對中括號 , 並 且在中括號內以數字來標示索引碼 , 指定要放入哪一 個元素中。  要特別注意的是 , 第 1 個保管箱的索引碼是 0 、第 2 個保管箱是 1 、 ... 、第 5 個保管箱是 4 。
  21. 21. 陣列的使用  這樣一來 , 就記錄好各個學生的成績了。  有了上面的內容之後 , 就可以用非常簡單的方式來計 算總和。
  22. 22. 陣列的使用  陣列本身除了可以放置資料外 , 還提供有許多項相關 於該陣列的資訊 , 稱為屬性 (Attributes) 。  其中有一項屬性 , 名稱為 length, 可以告訴我們該陣 列中元素的數量。要取得這個屬性的內容 , 只要在陣 列變數的名稱之後 , 加上 . length 即可。  有了這項資訊 , 再搭配迴圈 , 就可以依序取出陣列中 的資料 , 進行加總了。
  23. 23. 陣列的使用  這也就是 10 ~ 13 行所進行的工作:  其中 , 第 11 行的 students.length 就是取得 students 所指陣 列的元素個數。  在第 12 行中 , 就將每次迴圈所取出的元素加入 sum 變數中 , 以計算加總值。
  24. 24. 陣列的使用  最後 , 再利用陣列的 length 屬性值當除數 , 以算出 平均值:  如此 , 就完成用陣列計算成績平均的程式。
  25. 25. 超過陣列個數的存取  在使用陣列時 , 必須小心不要使用超過陣列最後一個 元素的索引碼 , 舉例來說 , 以下這個程式就會發生錯 誤:
  26. 26. 超過陣列個數的存取  由於陣列元素的索引碼由 0 起算 , 因此在第 9 行想 要設定 a[4] 的內容時就會出錯。  相同的道理 , 第 12 行中 , 迴圈結束的條件是 i <= a.length, 所以當 i 為 4 的時候 , 迴圈仍然會執行 , 但是 a 所指的陣列只有 4 個元素 , 最後一個元素的 索引碼為 3, 要存取 a [4] 的內容 , 自然會出錯:
  27. 27. 超過陣列個數的存取  對於還沒有習慣陣列的第 1 個元素索引碼為 0 的讀 者來說 , 這是很容易犯的錯 , 請特別留意。 ▪ 請特別留意迴圈的索引碼控制 , 避免存取到不存在的 元素。
  28. 28. 7-1-2 使用陣列的好處  瞭解了陣列的使用方法後 , 就可以回過頭來看看 , 使 用陣列到底有甚麼好處?  我們先比較看看 ArrayAverage.java 與 Average.java 這 2 個程式 , 從中發現 ArrayAverage.java 因為使用陣列而具有的優點。
  29. 29. 使用陣列的好處 ▪ 只需宣告一個陣列變數 , 而不需要宣告和學生人數相 同數量的變數。 當然 , 在配置陣列空間的時候 , 還是得依據學生人數 指定大小 , 但至少程式的行數仍然維持不變。 更重要的是 , 假設學生的成績是從檔案中讀取 , 學生 人數在讀取資料後才能確定的話 , 不使用陣列的方式 根本就無法處理 , 因為不但不知道該宣告多少個變數 , 而且也無法透過索引碼的方式使用這些變數。
  30. 30. 使用陣列的好處 ▪ 指定陣列元素的內容時雖然看起來和使用變數時一樣 的累贅 , 不過如果資料是從檔案中循序讀入的話 , 就 可以使用索引碼依序放入陣列的元素中。此時 , 若是 使用多個變數的方式 , 就沒有辦法做到了。 ▪ 可以使用索引碼存取陣列元素 , 這使得在進行陣列元 素加總之類的循序處理時非常方便 , 只要透過同樣的 程式 , 不論陣列多大 , 都一樣適用 , 而不需要去修改 程式。
  31. 31. 使用陣列的好處  從上述的說明應該可以瞭解 , 使用陣列已不單單是好 壞的問題 , 有些情況下 , 不使用陣列也就等於無法完 成任務 , 陣列反而是不可獲缺的要素了。
  32. 32. 7-2 陣列的配置與初值 設定  在上一節中 , 已經對於陣列的使用與優點有了基本的 認識。  接下來 , 就要詳細解說陣列在宣告、配置、以及設定 陣列元素的內容時 , 各種可能的作法。
  33. 33. 7-2-1 宣告同時配置  雖然陣列在實際運作時會區分為宣告變數以及配置陣 列兩段工作 , 不過在撰寫程式時卻可以簡化 , 將宣告 以及配置的動作合在同一個指定運算式中。  寫法很簡單 , 就是將原本宣告的敘述和配置空間的 new 運算子透過指定運算子串起來 , 像是剛剛的 ArrayAverage.java 就可以改寫成這樣。
  34. 34. 宣告同時配置  程式的執行結果完全和之前的程式一樣。
  35. 35. 宣告同時配置  前面曾經提過 , 配置陣列時 , 並不是只能用字面常數 來指定元素的個數 , 也可以使用變數或是運算式 , 例 如:  由於元素個數必須為整數 , 因此只有運算結果為整數 值 的運算式才能用來指定陣列的元素個數。
  36. 36. 7-2-2 設定陣列的初值  如果您的陣列是在撰寫程式的當時就已經知道個別元 素的初值 , 那麼您還可以再把計算平均成績的程式簡 化 , 在宣告的同時 , 直接列出個別元素的初值 , 替代 配置元素以及設定個別元素的動作 , 例如。
  37. 37. 設定陣列的初值
  38. 38. 設定陣列的初值 1. 要直接設定陣列的初值 , 必須使用一對大括號 , 列 出陣列中每一個元素的初值。 2. 記得要在右大括號後面加上分號 (;), 表示整個宣告 敘述的結束。  實際上這段程式在執行時的運作方式 , 和原來的程 式是一模一樣 , 只是在撰寫程式時可以比較便利而 已。  由於這樣的特性 , 因此在宣告中直接設定陣列內容 時 , 也可以使用運算式 , 而不單單僅能使用字面常 數。舉例來說。
  39. 39. 設定陣列的初值 ▪ 在宣告同時設定元素初值時 , 別忘了最後面大括號後 的分號 , 這是撰寫程式時很容易疏忽的地方。
  40. 40. 7-2-3 配合陣列使用迴圈  從本章一開始的範例到目前為止 , 您可能已經發現我 們經常會使用迴圈來依序處理陣列中的個別元素。  舉例來說 , 在 ArrayAverage.java 中計算平均成績 時 , 就使用了迴圈依序取出個別學生的成績 , 以便進 行加總。  而剛剛所介紹的 ArrayInitWithExpr.java 程式中 , 也 使用了迴圈依序顯示陣列中個別元素的內容。
  41. 41. 配合陣列使用迴圈  要進行這些工作 , 就必須自行撰寫迴圈 , 並且宣告迴 圈變數 , 然後透過迴圈變數做為索引碼 , 取出指定元 素的值。  為了避免這樣的麻煩 , Java 提供了另外一種 for 迴 圈的語法 ( 稱為 for-each 或 for-in 迴圈 ) , 方便陣 列的使用 , 請看以下這個範例。
  42. 42. 配合陣列使用迴圈
  43. 43. 配合陣列使用迴圈 1. for(:) 的作用 , 就是迴圈進行時 , 每一輪就從 ":" 後面所列的陣列取出下一個元素 , 放到冒號前面所 指定的變數中 , 然後執行迴圈本體的敘述。 2. ":" 前面的變數必須和陣列的型別一致 , 否則編譯時 就會發生錯誤。
  44. 44. 配合陣列使用迴圈  如果拆解開來 , 這個程式的第 5 ~ 7 行就相當於以 下這樣:  for-each 迴圈可以幫助我們撰寫出簡潔的迴圈敘述 , 除了陣列外 , 在第 17 章介紹集合物件的時候 , 還會 看到它的用處。
  45. 45. foreach 迴圈的注意事項  foreach 迴圈雖然好用 , 不過有 3 點需要注意: ▪ 實際上編譯器會把 foreach 迴圈拆解為一般的 for 迴圈 , 就像剛剛所展示的一樣。因此 , 使用 foreach 迴圈除了在 撰寫程式時有所差異以外 , 就和一般的 for 迴圈一模一樣 , 執行時的速度也不會有差別。 ▪ 在 for(:) 中的變數必須當場宣告 , 而不能使用事先宣告好 的變數 , 這是因為 Java 會直接將之拆解為宣告變數的形 式。因此像 int i; for(i : arr)... 這樣的寫法會造編譯錯誤 , 必須改為 for(int i : arr)... 。 ▪ 您必須使用 Java SE 5.0 ( 含 ) 以上的 Java 編譯器才能 編譯 foreach 迴圈 , 否則編譯時會有錯誤。
  46. 46. 7-3 多維陣列 (Multi-Dimensional Array)  由於陣列的每一個元素都可以看做是單獨的變數 , 如果 每一個元素自己本身也指向一個陣列 , 就會形成一個指 向陣列的陣列。  這種陣列 , 稱為 2 維陣列 (2 - Dimensional Array), 而 前面所介紹儲存一般資料的陣列 , 就稱為 1 維陣列 (1 Dimensional Array) 。  依此類推 , 您也可以建立一個指向 2 維陣列的陣列 , 其 中每一個元素都指向一個 2 維陣列 , 這時就稱這個陣列 為 3 維陣列。相同的道理 , 您還可以建立 4 維陣列、 5 維陣列、 ... . 等。  這些大於 1 維的陣列 , 統稱為多維陣列 , 每多一層陣列 , 就稱是多一個維度 (Dimension) 。
  47. 47. 7-3-1 多維陣列的宣告  要宣告多維陣列 , 其實和宣告 1 維陣列沒有太大的 差別 , 只要將 1 維陣列的觀念延伸即可。  舉例來說 , 要宣告一個所有元素都是指向 int 陣列的 陣列時 , 由於陣列中每一個元素都指向一個 int 陣列 , 因此可以這樣宣告:
  48. 48. 多維陣列的宣告  如果依循前面對於 1 維陣列宣告時的瞭解 , 可以把 int[ ] 當成是一種新的資料型別 , 表示一個用來儲存 int 型別資料的陣列。這樣一來 , 上述的宣告就可以 解讀為:  表示 a 是一個陣列 , 它的每一個元素都指向一個儲 存 int 型別資料的陣列。  如果套用之前所提的保管箱概念 , 這行宣告就等於是 說 a 保管箱中放置了一個組合櫃的號碼牌 , 而且組 合櫃中每一個保管箱本身又放置了另一個組合櫃的號 碼牌 , 也可以說像是一面組合櫃了。
  49. 49. 多維陣列的宣告  相同的道理,如果要宣告一個 3 維陣列,可以這樣 宣告:  我們可以解讀成 b 是一個陣列 , 它的每一個元素都 指向 int[ ][ ] 型別的資料 , 也就是一個 2 維的 int 陣列。如果套用組合櫃的觀念 , 這等於是一個立方體 的組合櫃了。  當然啦 , 在現實世界中 , 不會有人這樣設計組合櫃 , 否則被夾在中間的保管箱就沒法放入或是取出物品了 。  依此類推 , 您可以自行衍生宣告 4 維、 5 維陣列的 方式 , 不過在實務上很少會使用到這麼多維的陣列。
  50. 50. 7-3-2 多維陣列的配置  多維陣列的配置和 1 維陣列相似 , 只要使用 new 運算子 , 再指定各層的元素數量即可。例如:
  51. 51. 多維陣列的配置 1. 第 4 行就是實際配置 2 維陣列的空間 , 這就等於 是先配置一個擁有 3 個元素的陣列 , 其中每一個元 素各指向一個擁有 4 個 int 型別資料的陣列。 2. 由於 a 是指向一個擁有 3 個元素的陣列 , 所以 a.length 的值是 3 ;而個別元素 a[0] 、 a[1] 、與 a[2] 也各自是指向一個擁有 4 個元素的陣列 , 因 此 a[0].legnth 、 a[1].legnth 以及 a[2].legnth 的值都 是 4。
  52. 52. 多維陣列的配置
  53. 53. 分層配置  由於 a 是指向一個有 3 個元素的陣列 , 而每個元素 各自指向一個陣列 , 因此上述的程式也可以改寫成這 樣:
  54. 54. 分層配置 1. 第 4 行的意思就是先配置一個有 3 個元素的陣列 , 其 中每一個元素都是指向一個可以存放 int 型別資料的陣 列 , 這時尚未配置第 2 維的陣列。 2. 第 6 ~ 8 行就透過迴圈 , 幫剛剛配置的陣列中的每一個 元素配置 int 型別資料的陣列。事實上 , Java 在配置多 維陣列的時候 , 就是透過這樣的方式。
  55. 55. 分層配置  如果您使用這種配置方式 , 請特別注意只有右邊維度 的元素數目可以留空 , 最左邊的維度一定要指明。也 就是說 , 您不能撰寫以下這樣的程式:
  56. 56. 分層配置  但這樣就是可以的:
  57. 57. 非矩形的多維陣列  由於 Java 是以剛剛所說明的方式配置多維陣列 , 因 此我們甚至於還可以建立一個奇特的多維陣列 , 例如 :
  58. 58. 非矩形的多維陣列
  59. 59. 非矩形的多維陣列 1. 第 3 行宣告 a 指向一個擁有 3 個元素的陣列 , 每個元素都指向 1 個可以放置 int 型別資料的陣列 。 2. 第 5 ~ 7 行 , 分別為 a[0] 、 a[1] 、與 a[2] 配置了 不同大小的陣列。  Java 允許建立這樣的多維陣列。  如果以組合櫃的方式來描繪這種陣列 , 就會發現這 樣組合起來的組合櫃並不是矩形 , 因此稱為非矩形 陣列 (Non-Rectangular Array) 。
  60. 60. 非矩形的多維陣列
  61. 61. 非矩形的多維陣列 ▪ 由於多維度陣列只是陣列的陣列 , 所以可以有非矩形 的陣列 , 這是 Java 比較特別的地方 , 請多留意其結 構與原理。
  62. 62. 直接配置與設定多維陣列  多維陣列也和 1 維陣列一樣 , 可以同時配置並且設 定個別元素的內容。  只要使用多層的大括號 , 就可以對應到多維陣列的各 個維度 , 直接指定要配置的元素個數與元素內容 , 例 如。
  63. 63. 直接配置與設定多維陣列
  64. 64. 直接配置與設定多維陣列  在第 4 行中 , 就等於是宣告了 陣列變數 a, 指向一個 2 維陣 列 , 其中每個元素都指向一個擁 有 4 個整數的陣列 , 同時還設 定了個別元素的內容。
  65. 65. 多維陣列的使用  多維陣列的使用也和 1 維陣列一樣 , 只要在各維度 指定索引碼 , 就可以將指定的元素取出。  舉例來說 , a[2][3] 就是將 a 指向的多維陣列中第 3 排的組合櫃中的第 4 個保管箱的內容取出來。  如果是 a[2], 那就相當於是把 a 指向的多維陣列的 第 3 排組合櫃取出來 , 而您就可以將 a[2] 視為是 指向一個 1 維陣列的變數來使用。這些在前面的範 例中都已經示範過 , 相信大家都能夠瞭解。  另外 , 多維陣列也一樣可以和 for-each 迴圈搭配 , 例如。
  66. 66. 多維陣列的使用
  67. 67. 多維陣列的使用 1. 第 5 行 , 由於 a 指向一個 2 維陣列 , 因此這個 for-each 迴圈取出的元素是 int[ ] 型別。 2. 第 6 行 , 第 2 層的 for-each 迴圈取出來的才是 真正的資料。
  68. 68. 7-4 參照型別 (Reference Data Type)  在第 3 章曾經提過 , 陣列是屬於參照型別的資料 , 不過在當時因為還沒有實際介紹參照型別 , 因此對於 參照型別 , 並沒有著墨太多。  在這一小節中 , 就要詳細探討參照型別的特色 , 以及 相關的注意事項。
  69. 69. 7-4-1 參照型別的特色  我們以底下這個陣列為例來說明參照型別的特性:
  70. 70. 間接存取資料  參照型別的第一個特性是間接存取資料 , 而不是直 接使用變數的內容。舉例來說 , 當執行以下這行程 式時:  實際上進行的動作如下: 1. 先把變數 a 的內容取出來 , 得到號碼牌 15 。 2. 到編號 15 的組合櫃中 , 依據索引碼 2 打開組合櫃 中第 3 個保管箱 , 也就是號碼牌為 15-2 的保管箱 。 3. 最後 , 才進行指定運算 , 將 50 這個整數資料放入 保管箱中。
  71. 71. 間接存取資料
  72. 72. 間接存取資料  也就是因為在存取資料時 , 實際上是參照變數所記錄 的位址 ( 號碼牌 ) 去存取真正的資料 , 因此才稱之為 是參照型別。  由於必須透過間接的方式存取資料 , 因此存取的時間 一定會比使用直接存取資料的基本型別要久。  如果是多維陣列 , 那麼維度越多 , 間接參照的次數也 就越多 , 所花費的時間當然也就越久了。
  73. 73. 指定運算不會複製資料  先來看看以下這個程式:
  74. 74. 指定運算不會複製資料
  75. 75. 指定運算不會複製資料  a 和 b 的元素竟然一模一樣?  如果依照之前對於基本型別資料的觀念 , 那麼對於執 行的結果可能就會覺得奇怪。  陣列 a 不是應該是 20 、 30 、 40, 而陣列 b 應 該是 20 、 30 、 100 嗎?怎麼變成一樣的內容了 呢?
  76. 76. 指定運算不會複製資料  其實這正是參照型別最特別但也最需要注意的地方。  由於參照型別的變數所儲存的是存放真正資料的組合 櫃的號碼牌 , 因此在第 5 行的指定運算中 , 等於是 把變數 a 所儲存的號碼牌複製一個放到變數 b 中 , 而不是把整個陣列的元素複製一份給變數 b 。  這也就是說 , 現在 b 和 a 都擁有同樣號碼的號碼牌 , 也就等於是 b 和 a 都指向同一個組合櫃。
  77. 77. 指定運算不會複製資料
  78. 78. 指定運算不會複製資料  因此 , 接下來透過 b 對陣列的操作 , 就等於是對 a 所指陣列的操作 , 而現在 a 和 b 根本就是指向同一 個陣列 , 所以更改的是同一個陣列。 ▪ 請確實瞭解此一特性 , 這是考題中常見的陷阱。
  79. 79. 指定運算不會複製資料  事實上 , 對於一個陣列變數來說 , 也可以隨時變換整 個陣列 , 例如:
  80. 80. 指定運算不會複製資料
  81. 81. 指定運算不會複製資料  其中第 11 ~ 13 行就重新幫 a 配置陣列。  這個新的陣列和一開始所配置的陣列大小也不一樣 , 完全是新的陣列 , 也就是捨棄了原本的陣列 , 再配置 一個新的陣列給 a 。
  82. 82. 7-4-2 匿名陣列 (Anonymous Array)  前面介紹的 {1,2,3...} 語法 , 只能用在宣告陣列時做 為初始化之用。  如果要用在其他地方 , 例如重新配置陣列 , 則此語法 也可用來動態建立陣列 , 但必須在大括號之前加上 『 new 型別 [ ] 』 , 而成為匿名陣列 (Anonymous Array), 也就是沒有名字的實體陣列。例如:
  83. 83. 匿名陣列 (Anonymous Array)  另外有一點請注意 , 在宣告陣列時若有初始化 , 那麼 就不可在 [ ] 中指定數目。例如底下的程式:  上面程式的最後一行是正確的 , 但並未指定初值 , 此 時數值型別的元素預設為 0, 而字串元素則預設為 null 。
  84. 84. 重新配置陣列的注意事項  在重新配置陣列的時候 , 有一點要注意:重新配置時 可以先用 a = new int[2]; 來配置陣列元素 , 然後再 個別指定元素的值 ( 例如 a[0]=100;) ;或是也可使 用前面介紹過的匿名陣列 (a = new int[] {100, 200};) 。  但千萬不要直接以 {...} 來配置 , 例如以下是錯誤的 :  因為這並不是一個宣告陣列變數的敘述 , 而 {100,200} 的寫法只能用在宣告敘述之中。
  85. 85. 7-4-3 資源回收系統 (Garbage Collection System)  瞭解了上述參照型別的特色之後 , 您可能已經想到了 一個問題 , 如果不斷的配置陣列 , 也就是不斷的索取 組合櫃 , 會不會有組合櫃全部被佔用 , 沒有閒置的組 合櫃可用的情況?  為了避免這樣的狀況 , Java 設計了一個特別的機制 , 可以將已經閒置不再需要使用的組合櫃回收 , 以便供 後續需要時使用。這個機制就稱為資源回收系統。
  86. 86. 參照計數 (Reference Count)  為了讓資源回收系統能夠運作 , 就必須要有一套監控 組合櫃使用狀況的機制 , 這樣才能在發現有閒置的組 合櫃時 , 自動將之回收。  Java 的作法很簡單 , 它會監控對應於每一個組合櫃 的號碼牌個數 , 以剛剛看過的 ArrayAssignment.java 程式為例:
  87. 87. 參照計數 (Reference Count)  當程式執行完第 5 行後 , 變數 a 和 b 都擁有對應 同一個陣列的號碼牌 , 也就是該陣列目前已經發出了 2 個號碼牌。  這個數目稱為參照計數 (Reference Count), 因為它 記錄了目前有多少變數還握有同一個組合櫃的號碼牌 , 也就是還有多少變數可能會用到這個組合櫃。  有了參照計數後 , 資源回收系統就可以在某個組合櫃 的參照計數為 0 時 , 即認定不會再使用該組合櫃 , 因而回收該組合櫃。
  88. 88. 參照計數 (Reference Count)  那麼參照計數在甚麼狀況下才會減少呢?這可以分成 3 種狀況: ▪ 參照型別的變數自行歸還號碼牌:只要將參照型別的 變數指定為字面常數 null, 亦即: 就等於是告訴資源回收系統該變數不再需要使用所握 有的號碼牌對應的組合櫃 , 這時該組合櫃的參照計數 就會減 1 。
  89. 89. 參照計數 (Reference Count) ▪ 讓變數參照到其他組合櫃:參照型別變數只能握有一 個號碼牌 , 如果指派給它另一個組合櫃的號碼牌 , 像 是重新配置陣列 , 它就必須歸還原本的號碼牌 , 因此 對應組合櫃的參照計數也會減 1 。例如: 當執行了 a = b 之後 , {10,20,30} 這個陣列的參照計 數就減 1 了。 ▪ 參照型別的變數離開有效範圍 , 自動失效時。有關這 一點 , 會在下一章說明。
  90. 90. 參照計數 (Reference Count)  有了這樣的規則 , 資源回收系統就可以知道哪些組合 櫃還可能會再用到 , 而哪一些組合櫃不可能會再用到 了。
  91. 91. 回收的時機  一旦發現有閒置的組合櫃之後 , 資源回收系統並不會 立即進行回收的動作 , 而是先將這個組合櫃的號碼記 錄下來。  這是因為回收組合櫃的工作並不單單只是將其收回 , 可能還必須將組合櫃拆開 , 或是與其他的組合櫃集中 放置等搬移動作 , 這些動作都必須耗費時間。  如果資源回收系統在發現閒置的組合櫃的同時便立即 回收 , 就可能會影響到程式正在執行的重要工作。
  92. 92. 回收的時機  因此 , 資源回收系統會先將要回收的組合櫃記錄下來 , 等到發現程式似乎沒有在執行繁重的工作 , 像是等 待網路連線的回應時 , 才進行回收的工作。  透過這樣的方式 , 資源回收系統不但可以自動幫您將 閒置的資源回收 , 而且也不會影響到程式的執行效率 。  有關參照型別 , 在第 8 章介紹物件時還會提到 , 這 一節主要針對參照型別一般的特性以及與陣列相關的 部分做初步的瞭解。
  93. 93. 7-5 命令列參數: argv 陣列  雖然到了這一章才介紹陣列 , 但事實上之前所展示過 的每一個程式 , 都已經使用過陣列了。  如果您眼尖的話 , 一定會注意到每個程式 main( ) 方 法的小括號中 , 都有 String[ ] argv 字樣:  根據這一章所學 , 這個 argv 無疑是指向陣列的變數 , 而且其元素是用來儲存 String 型別的資料 , 也就 是字串。  但是這個 argv 有甚麼作用?又是從何而來呢?在這 一節中就要為您詳細的說明。
  94. 94. 7-5-1 argv 與 main() 方法  在第 2 章曾經說過 , main( ) 方法是 Java 程式的起 點 , 當我們在命令提示符號下鍵入指令要求執行 Java 程式時 , 例如:  Java 虛擬機器就會載入 ShowArgv 程式 , 並且從 這個程式的 main( ) 方法開始執行。  如果您的程式是用來顯示某個文字檔案的內容 , 那麼 可能就要將所要顯示的檔名傳入 , 此時就可以在指令 的後面加上額外的資訊 , 例如:
  95. 95. argv 與 main() 方法  這樣一來 , Java 虛擬機器就會配置一個字串陣列 , 然後將程式名稱 ( 以此例來說就是 ShowArgv) 之後 的字串 , 以空白字元分隔切開成多個單字 ( 以此例來 說 , 就有 2 個單字 , 一個是 test.html 、另一個是 readme.txt) , 依序放入陣列中。  然後 , 將這個陣列傳遞給 main() 方法 , 而 argv 就 會指向這個陣列。  因此 , 在程式中就可以透過 argv 取出使用者執行您 的程式時附加在程式名稱之後的資訊。
  96. 96. argv 與 main() 方法  請看底下這個程式:  程式中第 3 、 4 行就使用了一個 for 迴圈 , 將 argv 所指向的字串陣列的元素依序顯示出來。
  97. 97. argv 與 main() 方法  如果您使用以下指令執行這個程式:  執行的結果就會顯示:
  98. 98. argv 與 main() 方法  如果您要傳遞的資訊本身包含有空白 , 可以使用一對 雙引號 (") 將整串字括起來 , 例如:  其中的 this is a text 會被拆解為 4 個單字,如下:
  99. 99. argv 與 main() 方法  如果 "this is a text" 是單一項資訊 , 就得使用一對雙 引號括起來:  執行結果如下:  其中 "this is a text" 就被當作是一項資訊 , 而不會被 拆成 this 、 is 、 a 、 text 分開的 4 項資訊了。
  100. 100. 7-5-2 argv 陣列內 容的處理  由於 argv 指向的是一個字串陣列 , 因此不論在指令 行中輸入甚麼資訊 , 實際上在 argv 中都只是一串文 字。  如果您希望傳遞的是數值資料 , 那麼就必須自行將由 數字構成的字串轉換成為數值 , 這可以透過第 5 章 使用過的 parseInt( ) 來達成。  舉例來說 , 如果要撰寫一個程式 , 將使用者傳遞給 main( ) 方法的整數數值算出階乘值後顯示出來 , 像 是這樣:
  101. 101. argv 陣列內 容的處理  要得到 5 * 4 * 3 * 2 * 1 的值 , 那麼就必須將傳入的 字串 "5" 轉換成整數才行:
  102. 102. argv 陣列內 容的處理 ▪ 執行以上範例程式時 , 若未在程式名稱後面加上數值 、或故意加上非數字的參數 , 則執行時會發生錯誤 , 稱為『 例外』 , 解決例外的方式會在第 14 章說明 。 1. 第 5 行就是將字串轉換成整數 , 如果您要轉換的是 浮點數 , 可以改用以下的程式: 2. 在第 7 ~ 9 行中 , 就使用轉換出來的整數數值計算 階乘 , 並顯示出來。 1. 請注意 argv 是指向一個字串陣列。
  103. 103.  7-A 將陣列運用在查表上  7-B 搜尋 (Search) 資料  7-C 找出最大與最小值  7-D 排序(Sorting)
  104. 104. 1. Which statement s will legally declare and initialize an array? A. int [ ] a = {"1","2","3"} ; B. int [ ] a = {1,2,3} ; C. int [ ] a = [1,2,3] ; D. int [ ] [ ] a = {{1},{2},{3}} ; E. int [ ] [ ] a = {1,2} {3,4} {5,6} ; F. int [ ] a = new int [ ] {1,2,3} ; G. int [ ] a = new int [3] {1,2,3} ;
  105. 105. 2. Please drag and drop the appropriate code into the following empty boxes: Code:
  106. 106. 3. Given: Place the appropriate result to the end of the following two command line executions: java ArgShow Place result here java ArgShow a "b c" d Place result here
  107. 107. Result
  108. 108. 4. Given: Which, inserted at line 4, will compile? (choose three or four) A. char a; for(int i=0; i<b.length; i++) { a = b[i]; B. for(b : char a) { C. for(char a : b) { D. char a; for(a : b) E. for(char a, i=0; i<b.length; i++) { a = b[i];
  109. 109. 5. Given: Which statements are true? (Choose all that apply. ) A. Compiles error at L1. B. Compiles error at L2. C. Compiles error at L3. D. Compiles error at L4. E. Compiles error at L5.
  110. 110. 6. Given:
  111. 111. Which statements are true? (Choose a l l that apply. ) A. the array referenced by b is eligible for garbage collection at line 8. B. the array referenced by b becomes available for memory-recycling at line 10. C. the output is "193457". D. the output is "193458". E. the output is "123457". F. the output is "123458".
  112. 112. 7. Given: Which statement is true? A. This program will not compile. B. Runtime error at line 5. C. Runtime error at line 6. D. The result is 0,0. E. The result is 0,null. F. The result is null,null.
  113. 113. 8. Which are legal declarations? (Choose all that apply) A. int[] a = new int[3]; B. int b[3]; C. int c[] = new int[] {1,2,3}; D. int[] d = {1,2,3}; E. int[3] e = {1,2,3}; F. int f[] = new int[3] {1,2,3};

×