# JAVA 程式碼 ###### tags: `java` `運算` `陣列` `物件` `繼承` `多型` `介面` `例外` (一)專案 新增一個專案後,會建立相同的資料夾名稱和專案名稱(以本章節ex04 為例),所有的檔案都會放在這個資料夾中。 ![](https://i.imgur.com/KxQm93Z.png) (二)類別程式 在專案中新增一個類別程式(class),該檔案會存在src 資料夾中,副檔名為.java。如果在新增類別時有指定package,則會先建立一層子資料夾,再將類別程式放置其中,也會自動產生下列程式碼。 ![](https://i.imgur.com/It1xKJh.png) (三)預載類別套件 若程式會使用其他類別套件,可用import 預先載入類別程式庫,可運用* 萬用字元。 ![](https://i.imgur.com/70Zr5Cu.png) ![](https://i.imgur.com/qHK0bJY.gif) (四)Class 類別 Java 程式由類別組成,一個Java 程式中至少須包含一組類別宣告, 且需要與此檔案名稱相同。 ![](https://i.imgur.com/nwo59ln.png) (五)進入程式點(Entry point) 程式執行的起點稱為程式進入點,Java 程式進入點就是main() 方法。 ![](https://i.imgur.com/dwJOwv4.png) (六)執行區塊(Block) Java 程式使用大括號{ 和} 來區隔程式碼的範圍,左右大括號比須成對。為提高程式可讀性,程式碼應採內縮處理。 (七)敘述(Statement) 敘述或稱為陳述式是程式中的一行指令,敘述要以「;」結尾。 ![](https://i.imgur.com/6nQL5yn.png) (八)註解(Comment) ![](https://i.imgur.com/VCLYR3F.png) --- 範例: ```java= package ex04; import java.util.Scanner; public class Hi { public static void main(String[] arge){ Scanner scn = new Scanner(System.in); System.out.print("請輸入姓名"); String strName = scn.next(); System.out.println("Hi!"+strName+"歡迎來到JAVA世界!"); scn.close(); } } ``` > [color=#fcba03]練習 > ![](https://i.imgur.com/FTAUTWN.png) --- ## 識別字與關鍵字 (一) ==識別字== 在現實世界會為人和事物命名以便識別,設計程式時會對每個變數、類別、方法、物件及套件命名以便在程式中識別,這些變數、類別、物件等名稱就稱為識別字。識別字是由一連串的字元組合而成,程式編譯時,編譯器會將這些宣告的識別字視為變數名稱、欄位資料名稱、方法、類別、或是一個物件。 識別字以字母(a ~ z 或 A ~ Z)、底線(_)、或錢字號($)開頭。 識別字命名時必須遵守下列規則: - 識別字第二個字元後,只允許大小寫字母、數字、底線(_)、錢字號($)等字元。 - 字母大小寫視為不同字元,Ab 和AB 不同識別字。 - 識別字長度不限。保留字不允許當作識別字。 - Java 識別字可使用中文,建議以英文為主。 - 識別字中不可用特殊字元如:+、-、*、/、’…等。 - 識別字儘量使用有意義單字,以提高程式可讀性。 ![](https://i.imgur.com/qhS2skt.png) (二) ==關鍵字==(保留字) 關鍵字又稱「保留字」。是指程式語言事先定義好特別意義的識別字,設計時不可重複定義。Java提供的關鍵字如下: ![](https://i.imgur.com/BhXav8m.png) --- ## 變數與資料型態 ### 變數的宣告 - 在變數存入新值:指定變數成為一個全新值,並不能如同盒子一般,只取出部分金額。因為變數只能指定成一個新值,如果需要減掉一個值,其操作是先讀取變數值,在減掉後,再將變數指定成最後運算結果的新值。 - 讀取變數值:取得目前變數值,而且讀取變數值,並不會更改變數目前儲存的值。在程式語言中的「變數」(Variables)可以視為是一個擁有名稱的盒子,能夠在程式執行時暫時儲存所需的資料。 而當程式執行一直到程式結束,其值保持不變。例如:圓周率 3.1416,其值在程式執行過程不能改變,就屬==常數==(Constant)。 Java 使用變數前要先宣告,宣告變數時須賦予變數名稱,Java 允許同時指定初值, 將此動作稱為「初始化」(Initialization) 。告知編譯器該==變數屬於哪種資料型別==,便可知記憶體配置多少記憶空間來存放該變數內容。變數名稱命名方式遵循識別字命名規則。Java 變數宣告語法: ```java= 資料型別 變數名稱1[=初值1], [變數名稱2 [=初值2]…]; int year; int price = 10, qty; (qty未給值) = 178.8; float weight = 54.6F; char yesOrNo = 'y'; boolean ok = true; ``` > [color=#5ae2dc]範例1. 存取變數值 > ```java= package ex05; public class Ex05_01 { public static void main(String[] args) { int num1 = 80, num2 = 60; System.out.println("num1 = "+num1+", num2 = "+num2); System.out.println(num1+"+"+num2+"="+(num1+num2)); } } ``` ![](https://i.imgur.com/Ldlyiav.png) --- > [color=#5ae2dc]範例2. 定義資料型別 > ```java= package ex05; public class Ex05_02 { public static void main(String[] args) { final double PI = 3.1415926; double area; double r = 15.0; area = PI * r * r; System.out.print("面積:"); System.out.println(area); } } ``` ![](https://i.imgur.com/u75Oe5K.png) --- > [color=#5ae2dc]範例3. 變數存入新值 > ```java= package ex05; public class Ex05_03 { public static void main(String[] args){ int score1 = 35; int score2 = 10; int score3 = 10; score2 = 27; score3 = score2; System.out.println("第一節 = "+score1); System.out.println("第二節 = "+score2); System.out.println("第三節 = "+score3); } } ``` ![](https://i.imgur.com/kp8OB6B.png) --- ### 基本資料型態 變數共有byte、short、int、long、float、double、char和boolean八種資料型態。 ![](https://i.imgur.com/BLySVHl.png) #### 1. 整數型態 「整數資料型態」(Integral Types)是指變數資料為整數沒有小數點。整數型態資料可分為long、int、short、byte四種。 在Java程式碼可以直接使用包含0、正整數和負整數的「整數字面值」(Integral Literal),它可以使用十進位、八進位和十六進位表示,如下所示: 1. 二進位:「0b」開頭的整數值,每個位數值為0~1的整數。 2. 八進位:「0」開頭的整數值,每個位數值為0~7的整數。 3. 十六進位:「0x」開頭的數值,位數值為0~9和A~F(或a~f)。 ![](https://i.imgur.com/922VfiE.png) > [color=#5ae2dc] 進制換算 > ![](https://i.imgur.com/i0HSDPN.png) --- Java 提供long、int、short、byte四種整數型態最大值與最小值的代碼便於使用,最大值的代碼是MAX_VALUE ,最小值是MIN_VALUE。如要取用某型態的最大值或最小值,只要在這些代碼之前,加上所屬的類別全名即可。 ![](https://i.imgur.com/CxqXYBT.png) ![](https://i.imgur.com/oJk3Bwn.png) > [color=#5ae2dc] 整數溢位 > 當整數的大小超過可以表示的範圍,而程式中又沒有做數值範圍的檢查時,這個整數變數所輸出的值將發生紊亂,且不是預期中的執行結果,稱為「==溢位==」(overflow)。 ![](https://i.imgur.com/D70qO1P.png) > [color=#5ae2dc]修改後 > ![](https://i.imgur.com/ofzl6KE.png) --- #### 2. 浮點數型態 「浮點數資料型態」(Floating Point Types)是指整數加上小數,例如:3.1415926、12300.56789等。浮點數型態資料可分為float、double 兩種。 在Java 程式碼如果直接使用浮點數字面值(Floating Point Literal),其預設是double 資料型態,而不是float。我們也可以使用科學符號的「e」或「E」符號來代表10為底的指數。 |浮點數字面值|十進位值|說明| |---|---|---| |0.0123| 0.0123| 浮點數| |.00567 |.00567 |浮點數| |1.25e4| 12500.0 |使用e指數科學符號的浮點數| 如果浮點變數宣告的是float,在指定浮點數字面值時,因為預設是double,所以需要在浮點數字面值的==字尾加上字元「F」或「f」==,將數值轉換成浮點數float,如下所示: > [color=#5ae2dc]練習 > ![](https://i.imgur.com/CbI378l.png) 在 Java SE7(含)以後的版本提供底線"_"來分隔數值字面值,使得長串的數值變得容易閱讀。 --- #### 3. 布林型態 「布林資料型態」(Boolean Type)只能有2個值true 和false,這並不是變數名稱,而是Java 的關鍵字。程式中可用此型別來代表條件值,通常是使用在條件和迴圈控制的條件判斷,使得程式能做決策。Java的布林值和C與C++語言不相同,不允許使用 0 代表假,1 代表真。 --- #### 4. 字元型態 「字元資料型態」(Char Type)是「無符號」(Unsigned)的==16位元整數表示的Unicode字元==。Unicode使用2個位元組來表示字元,可以==取代ASCII字元==單一位元組的表示方式。 在Java 程式使用字元字面值(Char Literal)時,需要使用「'」單引號括起,如下所示: ```java= char a = 'A'; ``` 上述變數宣告設定初值為字元A,字元字面值是使用「'」單引號,而不是「"」雙引號括起。Unicode字元需要使用「\u」字串開頭的十六進位數值來表示,如下所示: ```java= char c = '\u0020'; ``` 字串字面值(String Literals)就是一個字串,字串是0或多個依序的字元字面值使用雙引號「"」括起的文字內容,如下所示: ```java= “Java程式設計” “Hello World!” ``` 在Java 語言的字串是一種字串物件,屬於參考資料型態,目前Java 程式碼的字串主要是使用在System.out.println() 或println() 方法的參數,如下所示: ```java= System.out.print("換行符號\n"); ``` Java語言提供Escape跳脫字元,這是使用「\」符號開頭的字串,可以顯示一些無法使用鍵盤輸入的特殊字元。 [[Unicode編碼參考]](https://zh.wikipedia.org/wiki/Unicode%E5%AD%97%E7%AC%A6%E5%88%97%E8%A1%A8) [[ASCII編碼參考]](https://www.ascii-code.com/) ![](https://i.imgur.com/6BHiZgn.png) ![](https://i.imgur.com/66xANgM.png) --- ### 資料型態的轉換 Java 的資料型態在定義時就已經決定,因此不能隨便改變成其他的資料型態,但Java 容許使用者有限度的進行型態轉換處理。資料型態的轉換可分為「自動型態轉換」及「強制型態轉換」兩種。 #### (一)自動型態轉換 Java會在下列條件皆成立時,自動進行資料型態的轉換: 1. 轉換前的資料型態與轉換後的型態相容。 2. 轉換後的資料型態之表示範圍比轉換前的型態大。 例如: int 和 float 相加,==int 會被轉成 float==。 char 和 int 相加,==char 會被轉成 int==。 型態轉換發生在運算子左右兩邊的運算元型態不同時。自動資料型態的轉換只限該行敘述透過自動型態的轉換,可以保證資料的精確度。這種轉換也稱為擴大轉換(augmented conversion)。 > [color=#5ae2dc]練習 > ![](https://i.imgur.com/KlfFQlf.png) #### (二)強制型態轉換 當執行兩個整數的運算時,運算的結果也會是整數。例如進行整數除法5 / 3 的運算,其結果是整數1 ,而不是實際的1.66666…,此時就必須進行資料型態的強制轉換。 變數強制轉換成另一種型態,原先的型態不會被改變。縮小轉換(narrowing conversion)可能會漏失資料的精確度。Java不會主動做縮小轉換 。 > [color=#5ae2dc]練習 > ![](https://i.imgur.com/u8WFRrQ.png) ### 使用者由鍵盤輸入資料 在程式語言裡,透過使用者從鍵盤輸入資料,不僅是程式的需求,更可以增加與使用者之間的互動。在使用Scanner 類別時,必須先建立Scanner 類別的物件,再利用所建立的物件呼叫相對應的函數。下表是輸入資料時==Scanner 類別==的函數: ![](https://i.imgur.com/mb8ZZ3c.png) 程式中若有需要輸入多項資料,可以只宣告一個Scanner 類別的物件,再==使用Scanner 類別提供的成員函數,將鍵盤中輸入的資料指定給不同型態的變數存放==,不需要宣告多個Scanner 類別物件,如下列範例: ![](https://i.imgur.com/1OEOIU8.png) #### 字母 **Scanner and nextChar() in Java** Scanner class in Java supports nextInt(), nextLong(), nextDouble() etc. But there is ==no nextChar()== (See this for examples) To read a char, we use ==next().charAt(0)==. next() function returns the next token/word in the input as a string and charAt(0) function returns the first character in that string. ```java= // Java program to read character using Scanner // class import java.util.Scanner; public class ScannerDemo1 { public static void main(String[] args) { // Declare the object and initialize with // predefined standard input object Scanner sc = new Scanner(System.in); // Character input char c = sc.next().charAt(0); // Print the read value System.out.println("c = "+c); } } ``` > [color=#5ae2dc]練習1 > ![](https://i.imgur.com/LIf2Xtk.png) ![](https://i.imgur.com/LIM0SMP.png) > [color=#5ae2dc]練習2-方法一 > [參考來源](https://marquee.pixnet.net/blog/post/44263225-java-7-%E7%B7%B4%E7%BF%92%E9%A1%8C%E8%A9%A6%E4%BD%9C-page-3-29-ex.22) ```java= import java.util.Scanner; public class HW3_29_22 { public static void main(String[]args) { Scanner scn = new Scanner(System.in); String english = "abcdefghijklmnopqrstuvwxyz"; System.out.print("Please input a word!!"); String str = scn.nextLine(); int i = english.indexOf(str); System.out.println(str+"為第" +(i+1)+ "個字母"); } } ``` ![](https://i.imgur.com/8RAonEk.png) > [color=#5ae2dc]練習2-方法二 > ![](https://i.imgur.com/5CQV7Tq.png) --- # 運算式與運算子 ### 運算式 運算式就是結合運算元(operand)與運算子(operator)所構成的計算式。運算元是指運算的對象,運算元可為變數、常值或是運算式,運算子是指可對運算元作特定運算符號(像+、-、*、/)。 ![](https://i.imgur.com/m2aXNjO.png) --- ### 運算子 Java提供許多運算子,這些運算子不但可以處理一般的數學運算,還可以進行指派與邏輯等運算。按照運算子性質分七大類: 1. 指定運算子(Assignment Operator) 2. 算術運算子(Arithmetic Operator) 3. 關係運算子(Relational Operator) 4. 布林邏輯運算子(Boolean Logical Operator) 5. 位元邏輯運算子(Bit Logical Operator) 6. 遞增和遞減運算子 (Increment & Decrement) 7. 移位運算子(Shift Operator) 運算子的優先順序如下: ![](https://i.imgur.com/48QkbxP.png) 運算子若按照運算時所需要運算元數目分成: 1. 一元運算子(Unary Operator) -10、++k 2. 二元運算子(Binary Operator) a + b 3. 三元運算子(Tenary Operator) max = a > b ? a : b; (一)指定運算子 指定運算子表示符號用等號(=),等號(=)並不是「等於」,而是「==指定==」。指定運算子會將等號右邊運算結果指定給等號左邊的變數。等號右邊可為運算式、常值或變數。 語法: 變數名稱 = [運算式|變數|常值] ; sum=num1+num2; (二)算術運算子 算術運算子就是常用的數學運算,其運算元是數值的變數或字面值,其中加法運算子還可以連接2個字串。包括:加法(+)、減法(-)、乘法(*)、除法(/)、負數(-)、取餘數(%)等: ![](https://i.imgur.com/bWcpui4.png) > [color=#5ae2dc]練習 > ![](https://i.imgur.com/t9PVOpH.png) > [color=#5ae2dc]練習 > ![](https://i.imgur.com/3LT3r7u.png) (三)遞增和遞減運算子 Java語言的「遞增和遞減運算字」是一種置於變數之前或之後的運算式簡化寫法,屬一元運算子,用來對目前的變數值作加1或減1。若將運算子放在變數前如:+ +a或- -a 稱為==前置式,變數在運算式使用前先進行加1或減1動作==。若將運算子放在變數後,a+ +或a- -稱為==後置式會先將變數值用於運算式中,後再對變數作加1或減1動作==。 > [color=#5ae2dc]練習 > ![](https://i.imgur.com/BbxbApc.png) (四)關係運算子 關係運算子又稱為比較運算子,可決定一個運算元與另外一個運算元間的關係,比較結果不是 true 或 false。==判斷成立與否,並非判斷對錯。==![](https://i.imgur.com/J8OSMzG.png) > [color=#5ae2dc]練習 > ![](https://i.imgur.com/mRz0UVV.png) (五)邏輯運算子 邏輯運算子又稱為條件運算子,條件判斷時可用邏輯運算子來連接兩個或以上的關係運算式。 ![](https://i.imgur.com/wHlUeuA.png) ![](https://i.imgur.com/P8lGXLl.png) [補充參考](https://blog.twtnn.com/2013/09/java.html) ![](https://i.imgur.com/k1NTJVG.png) ![](https://i.imgur.com/yW1YJ2z.png) > [color=#5ae2dc]練習 > ![](https://i.imgur.com/FB9N8RU.png) (六)位元運算子 位元(Bit)運算子是應用在整數資料型別和字元資料型別上,不是布林資料型別。這些資料型別的資料都可用二進位數字來表示,再對每個 Bit 做個別邏輯運算,每個 Bit 的運算結果不是0就是1。提供向左移或右移幾個位元的位移運算或NOT、AND、XOR和OR的位元運算。 ![](https://i.imgur.com/ADd5p2Z.png) 位元運算子-真假值表 ![](https://i.imgur.com/CgCG1UU.png) 1. NOT運算 (補數) 2. AND運算 AND運算「&」通常是用來將整數值的一些位元遮掉,也就是說,當使用「位元遮罩」(Mask)和數值進行AND運算後,可以將不需要的位元清成0,只取出所需的位元。 ![](https://i.imgur.com/94XIw0A.png) 3. OR運算 OR運算「|」可以將指定的位元設為1。 ![](https://i.imgur.com/da8hUQe.png) 4. XOR運算 XOR運算「^」是當比較的位元值不同時,即0和1,或1和0時,將位元設為1。 ![](https://i.imgur.com/n6oFANE.png) > [color=#5ae2dc]練習 > ![](https://i.imgur.com/hQaQ1SP.png) --- (七)位移運算子 Java語言提供向左移(Left-shift)、右移(Right-shift)和無浮號右移(Unsigned Right-shift)幾種位移運算。 ![](https://i.imgur.com/Gxp9bfG.png) 對於正整數來說,左移運算每移1個位元,相當於乘以2;右移運算每移1個位元,相當於是除以2。例如:原始十進位值3的左移運算,在最右邊補0,如下所示: ==00000011 << 1 = 00000110 ( 6)== ==00000011 << 2 = 00001100 (12)== 上述運算結果的括號就是十進位值。原始十進位值120的右移運算,因為是正整數,所以在最左邊補0,如下所示: ==01111000 >> 1 = 00111100 (60)== ==01111000 >> 2 = 00011110 (30)== > [color=#5ae2dc]練習 > ![](https://i.imgur.com/ByolXrv.png) --- # 流程控制 ### 一、關於流程控制 程式語言撰寫的程式碼大部分是一列指令接著一列指令循序的執行,但是對於複雜的工作,為了達成預期的執行結果,我們需要使用「流程控制結構」(Control Structures)來改變執行順序。流程控制使用時機是改變程式執行流向或程式中某些程式區段需重複執行多次。 1. 循序結構(Sequential) 循序結構是程式預設的執行方式,也就是一個敘述接著一個敘述依序的執行(在流程圖上方和下方的連接符號是控制結構的單一進入點和離開點)。 ![](https://i.imgur.com/eU2AR8B.png) 2. 選擇結構(Selection) 選擇結構是一種條件判斷,這是一個選擇題,分為是否選、二選一或多選一三種。程式執行順序是依照關係或比較運算式的條件,決定執行哪一個區塊的程式碼(在流程圖上方和下方的連接符號是控制結構的單一進入點和離開點,從左至右依序為是否選、二選一或多選一三種)。 ![](https://i.imgur.com/Cj8chIT.png) 3. 重複結構(Iteration) 重複結構就是迴圈,可以重複執行一個程式區塊的程式碼,提供結束條件結束迴圈的執行,依結束條件測試的位置不同分為兩種:前測式重複結構(下圖左)和後測式重複結構(下圖右圖)。 ![](https://i.imgur.com/fbHp5Pl.png) --- ### 二、條件判斷 條件判斷是利用上一章介紹的關係運算式,配合程式碼區塊建立的決策敘述,共分為單選(if)、二選一(if/else)或多選一(if/else/if 和switch)等方式,以及條件敘述運算子(?:)可建立單行程式碼的條件控制。 1. If 單選條件 if條件敘述是一種是否執行的單選題,決定是否執行程式碼區塊內的程式碼,如果條件運算式的結果為true,就執行程式碼。 > [color=#ce5112]練習 > ![](https://i.imgur.com/Uo0ldm7.png) --- 2. if/else二選一條件 單純if條件只是選擇執行或不執行程式碼區塊的單選題,進一步,如果是二選一情況的兩個執行區塊,可以加上else關鍵字,依條件決定執行哪一個程式碼區塊。 > [color=#ce5112]練習 > ![](https://i.imgur.com/vvGAzI6.png) --- 3. if/else/if多選一條件 if/else/if多選一條件敘述是if/else條件擴充的巢狀條件敘述,只需重複使用if/else條件建立if/else/if條件敘述,即可建立多選一條件敘述。 ```java= charAt() 方法 //用於返回指定索引處的字符。索引範圍为從 0 到 length() - 1。 Character類用於對單個字元進行操作,在對象中包裝一個基本類型 char 的值 ``` ![](https://i.imgur.com/Cp68mpk.png) [Character類方法參考](https://www.runoob.com/java/java-character.html) > [color=#ce5112]練習 > ![](https://i.imgur.com/6Dmmt6s.png) > [color=#ce5112]練習(巢狀式) > ![](https://i.imgur.com/Pz0jgE1.png) --- 4. switch多選一條件 if/else/if多選一條件敘述擁有多個條件判斷,當擁有4、5個或更多條件時,if/else/if條件很容易產生混淆且很難閱讀。所以Java語言提供switch多選一條件敘述來簡化if/else/if多選一條件敘述。 > [color=#ce5112]練習 > ![](https://i.imgur.com/H6kggNd.png) --- Switch 選擇敘述, case 區段最後一行必須加 break 。省略 berak 會不比對 case 值直接執行以下敘述。省略 break 可能造成非預期執行結果!撰寫程式時,不省略 default 避免碰到 case 值都不滿足產生問題。 > [color=#ce5112]練習(沒有加break的情況) > ![](https://i.imgur.com/Djg9tjB.png) > [color=#ce5112]正確寫法 > ![](https://i.imgur.com/v3gSTsM.png) --- ### 三、迴圈控制 迴圈控制執行敘述是撰寫程式時常用的敘述之一,主要功用能重複執行某項工作,直到符合終止的條件才會停止。Java 迴圈控制敘述有 for 和 while 和 do-while 三種。 1. for迴圈 在for迴圈的程式敘述中擁有預設計數器變數,計數器可以每次增加或減少一個值,直到迴圈結束條件成立為止。基本上,如果已經知道需重複執行幾次,就可以使用for計數迴圈來重複執行程式碼區塊。 > [color=#ce5112]練習 > ![](https://i.imgur.com/SwUKVJw.png) > [color=#ce5112]練習(巢狀式) > ![](https://i.imgur.com/7twSn01.png) --- 2. while迴圈 前測式while迴圈敘述需要在程式碼區塊自行處理計數器變數的增減,而且迴圈是在程式碼區塊開頭檢查條件,條件成立才允許進入迴圈執行。 > [color=#ce5112]練習 > ![](https://i.imgur.com/WeG7ayI.png) > [color=#ce5112]練習(巢狀式) > ![](https://i.imgur.com/o4cPcqj.png) --- 3. do/while迴圈 後測式do/while和前測式while迴圈的主要差異是在迴圈結尾檢查條件,因為先執行程式區塊的程式碼後才測試條件,所以do/while迴圈的程式區塊至少會執行「1」次。 > [color=#ce5112]練習 > ![](https://i.imgur.com/6Bq6xVl.png) --- ### 四、分支敘述 Java提供的分支敘述有 break、continue及 return 三種。分支敘述可控制程式碼執行到某個地方時,直接跳到另一個地方繼續執行。藉由這些分支敘述可使程式更輕鬆、更彈性達到預期目標。 1. break Java的break關鍵字可以強迫終止迴圈的執行,如同switch條件敘述使用break關鍵字跳出程式區塊一樣。 > [color=#ce5112]練習 > ![](https://i.imgur.com/7OQutfi.png) > [color=#ce5112]練習 > ![](https://i.imgur.com/Pbh2EWi.png) 2. continue Java的continue關鍵字是對應break關鍵字,配合break來決定程式在略過 continue 後 的程式碼時,重新回到break處。應用在 for、while、do-while 迴圈中,可略過 continue 後面程式碼不執行,直接回到迴圈開頭的運算式繼續進行。 > [color=#ce5112]練習 > ![](https://i.imgur.com/lD3RvNG.png) --- # 陣列 [[陣列參考資料]](https://caterpillar.gitbooks.io/javase6tutorial/content/c5_1.html) ## 一、關於陣列 「陣列」(Arrays)是程式語言的一種基本資料結構,屬於一種循序性的資料結構。Java語言的陣列就是Array物件,它是一種參考資料型態。因此,==Java陣列變數值並不是陣列本身,而是指向陣列真正位址的參考==。 使用陣列時機為需處理==多個同性質資料時==,用陣列取代多個同性質的變數。陣列先經宣告並用 ==new== 在記憶體建立該陣列連續空間給此陣列使用。陣列經宣告和 new 後,就可知陣列中含有多少個元素及每個元素是屬哪種資料型別。 陣列宣告方式: 1. 語法1:資料型別[] 陣列名稱; 語法2:資料型別[]陣列名稱; 語法3:資料型別陣列名稱[]; 設定陣列的初始值 ![](https://i.imgur.com/aCe1OAN.png) 2. 陣列變數= new 資料型別[ 陣列元素個數] ; ![](https://i.imgur.com/nNNwHLJ.png) ![](https://i.imgur.com/7GFGieS.png) ![](https://i.imgur.com/ZZBPmvr.png) ## 二、使用迴圈存取陣列的內容 1. **for 迴圈** > [color=#ce5112]練習 > ![](https://i.imgur.com/JvGEVDa.png) 2. **for-each 迴圈** 抓==全部資料==時,相較於for迴圈,較簡潔的寫法。 不適用於印部分資料。 ```java= for ( 陣列資料型別變數: 陣列) { 執行敘述句; } ``` > [color=#ce5112]練習 > ![](https://i.imgur.com/ugM64h4.png) --- ## 三、多維陣列 陣列索引只有一個稱為 一維陣列, 維度為1。兩個索引的陣列稱為 二維陣列 ,維度為2。如表格、座位表、兩班計概成績、一班的兩科成績,都用第幾列、第幾行(欄)表示,須用二維陣列描述。 陣列宣告時有三個索引為 三維陣列,維度為3。可想像成由好幾個教室疊起來立體大樓,指定第幾層的第幾列的第幾行,也是可表示任何一個位置。若陣列維度是二維以上稱為 多維陣列。 1. 建立二維陣列 ```java= 資料型別[ ][ ] 陣列名稱= new 資料型別[ 第一維長度] [ 第二維長度]; int[][] arr = {{1, 2, 3}, {4, 5, 6}}; //二列三行 ``` ![](https://i.imgur.com/v7wpWuP.png) ==(對稱型陣列)== ![](https://i.imgur.com/AhoMb1H.png) 2. 使用巢狀迴圈存取二維陣列的內容 > [color=#ce5112]for 練習 > ![](https://i.imgur.com/7WPgsSK.png) > [color=#ce5112]測試結果 > ![](https://i.imgur.com/dYWeNOv.png) > [color=#ce5112]for each 練習 > ![](https://i.imgur.com/fZmtvOO.png) :::info for-each 迴圈僅用來跑出最終值,無法像for迴圈一樣,將陣列的"行列"代入印出每一個元素值。(但可以單獨印出值) ::: --- ## 四、非對稱型陣列 對稱型陣列就是每一列的陣列元素個數都相同。非對稱陣列就是不規則多維陣列。 Java 多維陣列記憶體配置是由一個陣列中的元素再參考到另一個陣列。可用此方式建立非對稱型陣列。做法是先建一個只指定第一維長度的二維陣列,然後再依序為第一維的每一個元素建立另一個新的一維陣列(也就是第二維陣列)。如先建立第一維長度為 3 的二維陣列n[3][],然後再逐一為n[0]~n[3] 建立另一個新的陣列,而第一維陣列所建立的(參考到)陣列元素個素都不一樣,如此就構成一個非對稱型陣列。 ![](https://i.imgur.com/4WSG3BA.png) ![](https://i.imgur.com/N5ikK9B.png) > [color=#ce5112]練習 > ![](https://i.imgur.com/8oKMPqF.png) --- ## 五、陣列的排序與搜尋 陣列可處理較多筆資料。在陣列中找到指定的資料,就需透過搜尋功能。在陣列中搜尋一筆資料,通常先將資料按照某個條件排序,以加快搜尋的速度。排序和搜尋是陣列常使用的功能。 1. 氣泡排序法 氣泡排序法是最簡單易懂的方法。用氣泡排序法來排序陣列,就像把每個陣列元素當作空盒子,將兩個相鄰資料互相做大小比較,再依排序條件互換位置,其演算法則如下: ==Step1== 假設有32、24、11、48、15等五筆資料,要由小到大的排序。此時,先將這五筆資料依序放入aNum[0]~aNum[4] 的陣列中。 ![](https://i.imgur.com/6jgtM2f.png) ==Step2== 將兩個相鄰的陣列元素資料互相比較,由aNum[0]~aNum[4] 中找到最大值放入aNum[4]中,方法如下: 1.aNum[0]和aNum[1]相比較,若aNum[0]> aNum[1]則兩陣列值互換。 ![](https://i.imgur.com/U6xXkNj.png) 2.aNum[1]和aNum[2]相比較,若aNum[1]> aNum[2]則兩陣列值互換。 ![](https://i.imgur.com/zQgv1KN.png) 3.aNum[2]和aNum[3]相比較,若aNum[2]> aNum[3]則兩陣列值互換。 ![](https://i.imgur.com/YYqNaUe.png) 4.aNum[3]和aNum[4]相比較,若aNum[3]> aNum[4]則兩陣列值互換。 ![](https://i.imgur.com/aT7yGlQ.png) 五筆資料經過上面四次比較後,便可找出最大的元素值(48)放在aNum[4]中,這是第一個循環。 ==Step3== 比較aNum[0]~aNum[3] 中找到第二個最大值放入aNum[3]中,aNum[4]就不再加入比較。 ![](https://i.imgur.com/T7BLpTB.png) ==Step4== 比較aNum[0]~aNum[2] 中找到第三個最大值放入aNum[2]中,aNum[3]和aNum[4]就不再加入比較。 ![](https://i.imgur.com/6dcr07h.png) ==Step5== 比較aNum[0]~aNum[1] 中找到第四個最大值放入aNum[1]中,aNum[2]、aNum[3]和aNum[4]就不再加入比較。 ![](https://i.imgur.com/YfDLDqA.png) ==Step6== 最後剩下aNum[0]就是最小值(11),整理如下: 第一循環比較了4 次,得到最大值放在aNum[4]。 第二循環比較了3 次,得到最大值放在aNum[3]。 第三循環比較了2 次,得到最大值放在aNum[2]。 第四循環比較了1 次,得到最大值放在aNum[1]。 > [color=#ce5112]練習 > ![](https://i.imgur.com/NJsEoAe.png) > [color=#ce5112]測試結果 > ![](https://i.imgur.com/INt40Pn.png) --- 2. 循序搜尋法 (資料量小) 排序可將陣列元素排大小及更有效搜尋資料。循序搜尋法是最簡單搜尋方法,也是比較沒效率的搜尋法。方法是由第一筆資料逐一往後搜尋,一直到找到所要資料為止,或搜尋完全部資料為止。N筆資料用循序搜尋法,平均執行N / 2次比較,循序搜尋法常用於少量資料搜尋或未經排序資料搜尋。 > [color=#ce5112]練習 > ![](https://i.imgur.com/tPu8arJ.png) > [color=#ce5112]測試結果 > ![](https://i.imgur.com/QJuLQnx.png) --- 3. 二分搜尋法 (資料量大) 使用二分搜尋法尋找陣列中的資料,必須先將該陣列進行排序。二分搜尋法執行效率比循序搜尋法好。N 筆資料進行二分搜尋法,平均做 Log2N+1 次比較。 ==Step1== 假設n 陣列有九筆資料,要搜尋「67」這筆資料,首先將n 陣的每個元素由小到大排序。 ![](https://i.imgur.com/Altlie9.png) ==Step2== 進行由小到大排序後,先找出陣列中間元素的索引(下界值+ 上界值)/2,即為n[4]。 ==Step3== 搜尋的資料與陣到的中間陣到元素進行比較。 1.若欲搜尋的資料與中間陣列元素相同,表示已找到該資料。 2.若欲搜尋的資料與中間陣列元素不同,表示沒有找到該資料,接下來將搜尋一分為二: (1)若搜尋的資料大於n[4],表示資料是在n[5]~n[8] 之間。 (2)若搜尋的資料小於n[4],表示資料是在n[0]~n[3] 之間。 以本例要搜尋的資料67 大於n[4],因此下一步要搜尋的資料是在n[5]~n[8] 之間。 ![](https://i.imgur.com/p3dHRkR.png) ==Step4== 重複Step2 與Step3,一直到找資料才停止: 1.找到中間元素的索引n[6],比較搜尋資料67 與n[6]後搜尋資料小於 n[6]。 2.找到中間元素的索引n[5],比較搜尋資料67 與n[5]後相符,結束搜尋。 > [color=#ce5112]練習 > ![](https://i.imgur.com/cLDI0Dk.png) > [color=#ce5112]測試結果 > ![](https://i.imgur.com/pvTJA7z.png) --- ## 六、Arrays 類別的應用 Java提供Arrays 類別可協助快速完成有關陣列排序搜尋的演算法和程式寫法。Arrays類別位於java.util套件中,在程式開頭用import 引用後就可直接呼叫使用: ```java= import java.util.Arrays; ``` 1. ==sort 方法== Arrays 類別中提供sort 方法可進行陣列的排序,語法: ```java= import java.util.Arrays; //載入陣列套件 遞增排序: int[] num = new int[]{1, 9, 6, 2, 8, 4}; Arrays.sort(num); ``` ```java= import java.util.Arrays; import java.util.Collections; 遞減排序: Integer[] num = new Integer[]{1, 9, 6, 2, 8, 4}; Arrays.sort(num, Collections.reverseOrder()); ``` > [color=#ce5112]練習(遞增) > ![](https://i.imgur.com/q6zFeTL.png) > [color=#ce5112]練習(遞減) > ![](https://i.imgur.com/rhk8BX4.png) 2. ==binarySearch 方法== Arrays 類別中提供binarySearch 方法,對已經完成排序的陣列進行搜尋,找到資料後回傳該資料的索引鍵值,==找不到就回傳負值==,語法: ```java= Arrays.binarySearch(陣列名稱, 搜尋值); ``` binarySearch 方法找不到資料時,會將該資料排序==插入陣列適當的位置==,傳回傳為該索引鍵值的==負值再減1== 。 int [] num = new int [] {1, 2, 3, 5, 6}; int n1 = Arrays.binarySearch(num, 2); //n1 = 1 int n2 = Arrays.binarySearch(num, 4); //n1 = -4 (4應該排在[3],插入後3變-3,-3-1=-4) > [color=#ce5112]練習 > ![](https://i.imgur.com/DDeAoKE.png) > [color=#ce5112]測試結果 > ![](https://i.imgur.com/X0faTFr.png) --- # 方法 [[參考資料]](http://dns2.asia.edu.tw/~wzyang/slides/Java/Chen/SE7ch06.pdf) ## 一、 程序與函數 「程序」(Subroutines或Procedures)是一個擁有特定功能的獨立程式單元,可以讓我們重複使用之前已經建立的程序,而不用每次都重複撰寫相同功能的程式碼。 一般來說,程式語言會將獨立程式單元分為程序和函數二種,程序沒有傳回值;有傳回值稱為「函數」(Functions)。 不論是日常生活,或實際撰寫程式碼時,有些工作可能會重複出現,而且這些工作不是單一程式敘述,而是完整的工作單元,例如:在自動販賣機購買茶飲,此工作的完整步驟,如下所示: Step 1:將硬幣投入投幣口 Step 2:按下按鈕,選擇購買的茶飲 Step 3:在下方取出購買的茶飲 ![](https://i.imgur.com/l0aWuiB.png) 相信沒有人在幫忙買飲料時,每一次都說出左邊3個步驟,而會很自然的簡化成3個工作: 1. 購買果汁 2. 購買茶飲 3. 購買汽水 上述簡化的工作描述就是函數(Functions)的原型,因為我們會很自然的將一些工作整合成更明確且簡單的描述「購買??」。 程式語言也是使用想同觀念,可以將整個自動販賣機購買飲料的步驟使用一個整合名稱來代表,即【購買()】函數,如下所示: 1. 購買(果汁) 2. 購買(茶飲) 3. 購買(汽水) --- ## 二、 方法 在Java語言的程序是一種類別的成員,稱為「方法」(Methods),簡單的說,在Java語言撰寫的程序或函數稱為方法。 - 屬於類別的「類別方法」(Class Methods) - 屬於物件的「實例方法」(Instance Methods) 方法使用時機: - 寫程式常碰到某個敘述區段需在程式不同地方重複執行。 - 每次都要再重寫該敘述區段,程式會冗長。 - 會增加除錯和維護時的困難。 ### (1) 定義方法 Java 是屬==物件導向==程式語言,不允許方法以單獨型式存在,必須包含在某個物件之下,成為物件的方法之一。==方法就是物件專屬的函式==,所代表該物件的特殊行為。方法在定義時是由==方法標頭及程式區段==兩部份所構成。語法: ```java= [修飾子][static]<傳回值型別><方法名稱>([引數串列])[throws<例外名稱>]{ ...... [程式區段;] [return 運算式;] ...... } //中括號為可省略,定義方法時不用打: public static void main(String[] args) ``` Java 是屬物件導向程式語言,不允許方法以單獨型式存在,必須包含在某個物件之下,成為物件的方法之一。方法就是物件專屬的函式,所代表該物件的特殊行為。方法在定義時是由方法標頭及程式區段兩部份所構成。語法: > [color=#ce5112]練習 > ![](https://i.imgur.com/kNTXZI8.png) --- ### (2) 呼叫方法(靜態) 若類別中的方法使用 ==static 宣告成靜態方法==, 則可直接呼叫使用。兩種寫法都屬呼叫敘述: ```java= 語法1:[類別名稱.]方法名稱([引數串列]) 語法2:變數 = [類別名稱.]方法名稱([引數串列]) ``` > [color=#ce5112]練習 > ![](https://i.imgur.com/HajI3PV.png) --- ### (3) 呼叫方法-物件實體(非靜態) 呼叫類別==不用 static== 宣告的靜態方法,必須先用 ==new== 建立該類別的實體 -物件。此時該==物件擁有該類別所有方法與資料成員==。 接著用「==物件.方法名稱(引數串列)==」方式呼叫該方法。每個用類別建立物件都擁有該類別的方法或資料成員。 > [color=#ce5112]練習 > ![](https://i.imgur.com/rPUxS6V.png) --- :::info Ex: 建立由n 加到m 總和total = n+(n+1)+(n+2)+…+m 的方法,不將結果傳回。呼叫方法分別求1 到10 及5 到12 的總和。 ::: > [color=#ce5112]練習 > ![](https://i.imgur.com/OvLDpxc.png) --- :::info Ex: 建立由n 加到m 總和total = n+(n+1)+(n+2)+…+m 並可回傳結果值的方法,使用return 敘述呼叫方法分別求1 到10 及5 到12 的總和傳回。 ::: > [color=#ce5112]練習 > ![](https://i.imgur.com/bvTyfuB.png) --- ## 三、 傳值或傳址呼叫 Java方法傳入的參數有兩種不同的參數傳遞方式,如下表所示: ![](https://i.imgur.com/RZJGlHd.png) ### (1) 傳值呼叫 方法中的虛引數果宣告為基本資料型別==char、byte、short、int、long、float、double、boolean== 八種型別變數。表示該方法的引數傳遞方式為傳值呼叫。 基本資料型別的變數是存放在Stack儲存空間,方法若為傳值呼叫,則呼叫敘述的實引數與被呼叫方法的虛引數是佔用不同記憶體使用傳值呼叫可防止變數被方法更改。 ![](https://i.imgur.com/M08voA5.png) > [color=#ce5112]練習 > ![](https://i.imgur.com/WDJZ8Fh.png) --- ### (2) 傳址呼叫 方法中的虛引數若==宣告==為參考資料型別如==陣列、物件==(變動性比較小)…等表示將此方法的引數傳遞方式設為傳址呼叫: - 呼叫敘述的實引數與被呼叫方法的虛引數兩者==佔用同一記憶體位==。 - 引數傳遞時,呼叫敘述中的實引數是將自己本身的記憶體位址傳給被呼叫方法的虛引數。 傳址呼叫傳遞引數的好處是被呼叫方法可==透過該引數將值傳回給呼叫敘述==。 > [color=#ce5112]練習 > ![](https://i.imgur.com/a9ks5Sg.png) [[定義類別參考資料]](https://openhome.cc/Gossip/Java/Class.html) --- ## 四、 方法間傳遞陣列引數 ### (1) 以陣列當引數 整個陣列當引數傳遞給方法,在被呼叫方法虛引數或資料型別後加上 [ ],即表示傳來的引數必須是陣列型別。陣列當引數是屬參考呼叫,方法對陣列執行結果會影響原呼叫敘述陣列值。 呼叫方法時引數只寫陣列名稱,後面不可加 [ ] 括號。 > [color=#ce5112]練習 > ![](https://i.imgur.com/ydtW4oV.png) --- ## 五、 方法過載 (method overloading) 方法過載或稱超載、覆載,就是在同一個類別中,允許方法使用相同的名稱,但是後面所接的引數串必須資料型別不同、個數或順序不同。 ![](https://i.imgur.com/ksNYEV5.png) > [color=#ce5112]練習 > ![](https://i.imgur.com/C3Mbldm.png) --- Java 提供省略引數個數語法來解決上述問題,語法: ```java= [修飾子][static]<傳回值型別><方法名稱>(<傳回值型別>...變數) ``` > [color=#ce5112]練習 > ![](https://i.imgur.com/XLGYWzC.png) :::info Ex: 建立兩個名稱皆為min 的靜態方法,第一個方法可以取得兩個整數中的最小值,第二個方法則可以取得整數陣列中的最小值。 ::: > [color=#ce5112]練習 > --- ## 六、遞迴 (Recursive) 遞迴是方法中有一行敘述再呼叫自已方法本身,使用遞迴時會不斷地呼叫方法自己本身。必須在遞迴的方法中設定條件來結束方法的執行,避免形成無窮迴圈。當滿足條件時才結束呼叫方法本身,才能結束遞迴。遞迴常用在具有規則性運算的程式設計如:求最大公因數、排列、組合、階層、費氏數列…等。 ![](https://i.imgur.com/wL2ERlr.png) Ex: 利用遞迴來算出費式數列 ![](https://i.imgur.com/PuvMqTm.png) ![](https://i.imgur.com/4gRLjRo.png) > [color=#ce5112]練習 > ![](https://i.imgur.com/zqYQwSP.png) --- :::info 建立大樂透開獎程式,執行時會以亂數方式顯示1~49之間7 個不重複的亂數。 ::: > [color=#ce5112]練習 > --- # 物件與類別 ## 一、物件導向程式設計概述 傳統的「程序導向」程式設計是將資料和處理的方法分開思考。由程式取得資料經處理後再回存,資料處於被動。當軟體規模愈大,資料和處理方法間相依度增高。 開發程式初期速度快,愈往後階段因修改、需求變更、維護等問題,愈顯得捉襟見肘。隨著軟體規模日益膨脹,以結構化技術分析的程序導向程式設計已無法應付目前日趨複雜的軟體的需求。 ==「物件導向」程式設計(Object Oriented Programming,簡稱OOP==。它是將資料和處理的方法一併思考並封裝在物件內。當軟體規模愈大時,由於具有資料抽象化以及封裝的特性,可使得資料和處理方法間的相依關係侷限在個別的物件範圍內。 這就是為什麼使用物件導向程式設計來開發程式,愈往後階段的開發速度會比程序導向程式設計快的原因。物件導向程式設計是以站在較人性化的觀點為思考模式,應用到各種領域的一種技術,它為電腦資訊業帶來革命性的突破。 ### (1) 物件 生活中所有東西都可以叫做「物件」(Object)。==物件的屬性(Attributes)和行為(Behaviors)兩項性質可來描述不同物件的特微==。 「屬性」是客觀且明顯的特徵。例如:Peter是一個人,Peter是一個物件,而Peter的姓名、性別、年紀、身高、體重…等,就是Peter的屬性。 「行為」就是這個物件「會做什麼事」,或者說「有什麼功能」。不同的物件可能擁有相同行為,也可能有不同行為。譬如:鳥的移動行為是「在空中飛」;魚的移動行為是「在水中游」,而它們也許有個共同行為就是「吃東西」。 ### (2) 類別 類別是用來定義具有相似性質物性的資料成員(屬性)和方法成員(行為)。可以用來描述物件的統。例如:人這個類別有身高、體重…等屬性,也有吃飯、移動的方法,利用人類這個模子所製作出來的物件有:小明、小華。 「小明」與「小華」都屬於「人」這個類別,但要注意「小明」與「小華」是不同物件,因為他們的屬性值不盡相同。他們的行為模式會有所差異。 --- ## 二、類別與物件的關係 物件導向程式設計是==利用類別來描述物件的建構方式==,而物件(Object)是按照類別的描述所建構出來的一個實體(Instance)。因此==在建立物件之前要先定義類別==。 以汽車為例:它具有最多載油量(gas)與平均耗油量(tbo)這兩個==屬性==,以及具有一次填滿油時可以行駛最長距離的==方法==(max_dist),若把最多載油量、平均耗油量這兩個屬性和行駛最長距離的方法==封裝==起來,則就成為一個汽車類別。 利用這個「汽車類別」(類別名稱為Ccar)可以建立出最多載油量、平均耗油量不同的car1與car2汽車物件,而這部兩汽車一次填滿油時,可以行駛的最長距離當然是不相同的。 ### (1) 如何定義類別 一個 Java 程式至少有一個或一個以上的類別。類別是由「資料成員」(屬性、欄位)和「方法成員」(方法、函式)封裝而成的,而一個類別至少含有其中一種成員。語法: ![](https://i.imgur.com/BxjPpxp.png) 注意事項: :::warning 1. 類別名稱建議以==大寫英文字母==為字首。 2. 成員存取修飾子有:==private(私有成員)、public(公開成員)、protected (保護成員)及預設階層(default即是不宣告)四種==。其中private私有成員只供自身類別內部成員存取。public公開成員不受任何限制,可供外界直接存。 3. 類別存取修飾子有public與預設階層(不宣告)兩種,==屬於public的類別可在不同套件使用==。若為==預設階層,只能用在相同套件==。 4. 一個 *.java程式檔可以定義多個類別,但==只能宣告一個public==的類別,且public的類別名稱須和程式檔名相同。 ::: > [color=#ce5112]練習 > ![](https://i.imgur.com/JEHsOd3.png) --- ### (2) 如何建立物件 由於int 是Java的資料型別,我們可以直接透過「int num ;」敘述來宣告屬於整數資料型別的變數num。在上節已使用class定義好Ccar類別,透過該類別名稱Ccar可以來宣告屬於該類別的物件car1和 car2,其寫法為「Ccar car1, car2 ;」。 以上一小節Ccar汽車類別而言,在主程式的main()方法中,可建立出最多載油量(gas)為40公升、平均耗油量(tbo)為每公升13.6公里的car1汽車物件,也可建立出最多載油量(gas)為60公升、平均耗油量(tbo)為每公升9.5公里的car2汽車物件。 這兩個汽車物件car1、car2,雖由同一類別Ccar宣告出來,卻是不一樣的物件,因為它們兩個的最多載油量屬性值與平均耗油量屬性值不同。所以說,==物件各自擁有自己的資料成員和方法成員==。下圖即是本例的記憶體配置情形。 ![](https://i.imgur.com/c54J5EW.png) --- ### (3) 物件的宣告與建立 Java宣告和建立物件的方式有下面兩種: ![](https://i.imgur.com/mtle7gu.png) ![](https://i.imgur.com/9Rv0VO5.png) --- ### (4) 如何存取public的資料成員 當car1、car2物件被建立後,由於gas、tbo、 max_dist屬性,以及maxDist()、dist()方法的存取修飾子都設為public公開成員,因此要從物件的資料成員(或稱屬性)中存取(設定或讀取)上述成員的資料時,只要在物件名稱與屬性名稱之間使用「.」運算子連結就可以。如: ![](https://i.imgur.com/mJ6rmTz.png) --- ### (5) 如何呼叫public的方法成員 其他類別的要呼叫car1物件公開(public)的方法成員,在方法名稱前一樣要加上物件名稱並用==點「.」運算子隔開==。如: ![](https://i.imgur.com/xZmFd9z.png) > [color=#ce5112]練習 > ![](https://i.imgur.com/3Yn2AeN.png) > [color=#ce5112]結果測試 > ![](https://i.imgur.com/IPedk7R.png) --- ### (6) 如何封裝成員資料 - 封裝是使用成員存取修飾子,來定義類別內部的資料成員和方法成員的存取限制,其目的用來保護類別內部的成員,免於受到外部程式的不當存取。類別內部成員被呼叫或存取的限制有下列情況: 1. 當資料成員或方法成員只允許給==自身類別或繼承自身類別的子類別呼叫存取==時,這類成員在定義時要使用==protected== (保護)成員存取修飾子來宣告。 2. 當資料成員或方法成員允許給==任何類別的程式敘述呼叫存取==時,這類成員在定義時要使用==public== (公開)成員存取修飾子來宣告。 3. 當資料成員或方法成員只允許給==自身類別內的程式敘述呼叫存取==時,這類成員在定義時要使用==private== (私有)成員存取修飾子來宣告。 - 以前面的汽車類別Ccar為例,Ccar類別的兩個資料成員gas(最大載油量)、tbo(平均耗量) 的成員存取修飾子是==用public宣告,其內容可以被類別外部任何程式敘述存取==。其實一部車的gas(最大載油量)、tbo(平均耗量)是唯讀的資料,不該任意由類別外部的程式敘述來任意存取。 - 開發具有物件導向程式的應用程式,若要防止資料成員被其他類別程式敘述存取,必須在定義類別時,將資料成員的成員存取修飾子設為private宣告成「私有成員」,只允許類別內的成員存取。至於類別內方法成員也是一樣,使用成員存取修飾子private把方法成員宣告成「私有成員」,則外部程式敘述便無法直接存取。 > [color=#ce5112]練習 > ![](https://i.imgur.com/MQ5VqFF.png) ![](https://i.imgur.com/RR3RrnQ.png) --- ## 三、方法多載 (Overload) 「多載」是指==同一個類別內,有兩個以上相同名稱的方法==,但是因為各個方法所要傳入的引數個數不同,或者是引數的資料型別不同,則這些方法將被視為不同,且各有各自的內容。當程式呼叫這類的方法時,怎麼知道到底要使用那個方法呢?==Java 編譯系統會自行去尋找引數條件符合的方法==,不會有不清楚情形發生。 > [color=#ce5112]練習 > ![](https://i.imgur.com/0VRHEiv.png) --- ## 四、建構式 在上節中,物件中資料成員的==初值是透過傳遞引數的方式==來設定。這個動作如果是在建立物件時,就能同時傳遞引數來進行資料成員的==初始化==工作,這就是使用類別的建構式(Constructor)。方式如下: ```java= 類別名稱 物件名稱 = new 建構式名稱(引數串列); ``` 1. 建構式名稱必須和所屬的類別名稱==相同==,物件在用new建立的同時,便自動執行此類別的建構式。 2. ==建構式必須寫在定義類別內==,定義方式與方法相似。若類別內未定義建構式,系統自動提供一個不帶引數的空敘述稱為「預設建構式」。當類別用new建立物件時,便自動執行這個預設的建構式。例如: ```java= Ccar car1 = new Ccar(); Ccar是類別名稱,也是建構式名稱,而Ccar()為預設建構式。 ``` 3. 建構式沒有傳回型別,即==不能用void與return==。 4. 建構式也==可以多載==,其做法和方法多載一樣,是使用不同引數串列的個數和引數串列的資料型別不同來加以區隔。 > [color=#ce5112]練習 > ![](https://i.imgur.com/4hDQDTx.png) > [color=#ce5112]測試結果 > ![](https://i.imgur.com/ybH5fJ5.png) --- ## 五、靜態成員 在類別中,其資料成員或方法成員在宣告時,若在修飾詞後面加上 static便成為「靜態成員」或稱「類別成員」。使用類別的公開靜態成員,可以直接透過類別來呼叫這個成員,即「類別名稱.成員名稱」。當一個資料成員或方法成員,只要使用public static宣告,它就允許在所屬類別建立物件之前被使用。 main()方法前一定都加 static。因為 main() 是程式執行的起點,在任何物件產生前,main()方法須先執行。不論相同的類別產生幾個物件,這些物件都可共用靜態成員。而static靜態成員在記憶體內永遠只會儲存一份,不像其它的成員,會隨著物件而個別產生。一般資料成員為物件的欄位變數,一般方法成員為物件方法。而靜態資料成員為類別變數,靜態方法為類別方法。 > [color=#ce5112]練習 > ![](https://i.imgur.com/vyPFDjE.png) > [color=#ce5112]測試結果 > ![](https://i.imgur.com/YH35LPu.png) --- ## 六、this參考自身類別 當類別中使用自己的資料成員或是方法成員時,為了能夠清楚得知這個成員是不是屬於類別中的成員,就可以利用this這個保留字來解決名稱重複的問題。 > [color=#ce5112]練習 > ![](https://i.imgur.com/sfciD0T.png) --- # 繼承、介面與多型 ## 一、繼承 物件導向程式設計,可將類別內的成員授予其它類別來「繼承」(Inheritance),我們將被繼承的類別稱為「父類別」(Superclass),而繼承別人的類別稱為「子類別」(Subclass)。 子類別除了繼承父類別所定義的資料成員和方法成員外,還可以再自行新增資料成員和方法成員,使得子類別能夠提供更多的功能。 下圖中最上層的腳踏車是單車的祖先,然後下層的單車是它的下一代(子代),分別有登山車、公路車和協力車,下一代的單車是繼承上層的腳踏車而來的。 ==繼承可縮短開發時間,減少重複寫相同的程式碼。== ![](https://i.imgur.com/gspkOvW.png) ### (1) 繼承的實作 實作繼承這項功能就要用到extends這個保留字,現在先看一下它的使用語法: ```java= class 子類別名稱 extends 父類別名稱{ . . (敘述區段) . } ``` 注意事項: :::warning 1. 一個父類別可以衍生出很多的子類別,但一個子類別只能繼承一個父類別。子類別可以將父類別已定義的成員當成基礎成員,進而擴充其它功能。 2. 子類別可以繼承父類別用public修飾子所宣告的成員,而該成員可在同一套件或不同套件內的類別所建立之物件使用。 3. 子類別可以繼承父類別用protected修飾子所宣告的成員,而該成員可在同一套件內的類別所建立之物件使用,但不同套件的類別所建立之物件不能使用。 4. 子類別不能繼承父類別用private修飾子所宣告的成員,但該相同名稱的成員在子類別中可另外定義,只是兩者被視為不同成員,彼此互不影響。 ::: > [color=#ce5112]練習 > ![](https://i.imgur.com/brLFyNk.png) --- ### (2) 多代的繼承 繼承是可以多代進行的,也就是說,可以父傳子、子傳孫…。而且,只要是有繼承關係的類別,自然就能繼承上層(上一代)的所有成員,也就是孫子也擁有父親的資料成員和方法成員,就算是曾孫、玄孫……也都會有前面各代類別的成員。多代繼承的語法如下: ![](https://i.imgur.com/Skv8pVA.png) > [color=#ce5112]練習 > ![](https://i.imgur.com/dxKVFiq.png) --- ### (3) 方法覆寫 「覆寫」(Override)是指如果子類別和父類別有相同的方法時(名稱一樣,引數的個數一樣,引數的資料型態也一樣,但方法的內容不相同),此時用子類別產生出來的物件,當使用到這個方法時,子類別的方法會覆蓋掉父類別同名稱的方法,也就是說程式會選擇子類別的方法來執行。 > [color=#ce5112]練習 > ![](https://i.imgur.com/lspYR3P.png) --- ### (4) 預設建構式的執行順序 如果利用子類別產生一個物件的時候,子類別的父類別、以及父類別的上一層類別的預設建構式(無引數建構式)都會執行。執行預設建構式先後次序是由最上層類別預設建構式先執行,依序往下層執行至該層的預設建構式為止。 > [color=#ce5112]練習 > ![](https://i.imgur.com/A6AAmFE.png) * protected和private成員的方法,只能用和類別相同的名稱。 :::spoiler ==protected成員==(點擊詳細) 在之前您的資料成員都預設為"private"成員,也就是私用成員,私用成員只能在類別物件中使用,不能直接透過物件來呼叫使用,而即使是擴充了該類別的衍生類別也是如此,您只能透過該類別所提供的"public"方法成員來呼叫或設定私用成員。 然而有些時候,您希望擴充了基底類別的衍生類別,能夠直接存取呼叫基底類別中的成員,但不是透過"public"方法成員,也不是將它宣告為"public",因為您仍不希望這些成員被物件直接呼叫使用。 可以宣告這些成員為「被保護的成員」(protected),保護的意思表示存取它有條件限制以保護該成員,當您將類別成員宣告為受保護的成員之後,繼承它的類別中就可以直接使用這些成員,但這些成員仍然受到物件範圍的保護,不可被物件直接呼叫使用。 要宣告一個成員成為受保護的成員,就使用"protected"關鍵字,下面這個程式是個實際的例子,您將資料成員宣告為受保護的成員,擴充它的類別中就可以直接使用,而不用透過"public"方法成員來呼叫: ::: --- ### (5) 使用super super通常有兩種用途,第一是讓子類別用來呼叫父類別的建構式,第二是在子類別中透過super來呼叫父類別的成員。語法如下: ![](https://i.imgur.com/EXrgP8c.png) > [color=#ce5112]練習 > ![](https://i.imgur.com/PE3BbjK.png) --- ### (6) 使用final final保留子可讓資料成員以常數表示。當使用final來宣告一個常數時,記得一定要同時給予這個常數初值(常數的值不能被變更的)。final如果應用在方法成員上,就表示這個方法不可以被子類別覆寫。換言之,如果父類別的某個方法成員前面加上了final保留字,則子類別又有相同名稱的方法成員的話,編譯時期就會出現錯誤。如果在class之前加上final時,則表示該類別無法被繼承。 > [color=#ce5112]練習 > ![](https://i.imgur.com/mDDx1gb.png) 覆寫的定義: :::warning 1. 是指子類別中如和父類別中有相同名稱和資料型別的方法,而且傳入的引數也相同。利用子類別產生的物件在呼叫這個方法時,會執行子類別的方法而不會執行父類別的方法。 2. 如對父類別的方法使用保留字 final,則子類別就不可用覆寫功能。 3. 如子類別取個相同名稱的方法,但傳入的引數不同,或是方法型別不一樣,還是可成立的。 4. 這種情形是多載不是覆寫。 ::: > [color=#ce5112]練習 > ![](https://i.imgur.com/ev4HYE3.png) --- ### (7) 靜態成員的限制 使用static需受到一些限制,包括下面兩點: 1. static方法成員只可以使用static資料成員,和呼叫static方法成員。 2. 類別中如果有static 方法成員,它的子類別不可以又有相同的static方法成員,也就是不可以有方法覆寫的情形發生。 > [color=#ce5112]練習 > ![](https://i.imgur.com/kpJLjpT.png) --- ## 二、抽象類別與抽象方法 「抽象類別」是一種無法具體化的類別。如果有一家汽車公司,老板提出開發新型車的構想,但是沒有交代詳實細節,就交給研發部門去實際作業。這時候,研發部門收到的訊息只是一個沒有具體化的抽象概念,不同的研發部門會因此開發出許多種不同的車款。這種的觀念若應用在程式設計上,則老板交辦下來的構想,就是一種「抽象類別」。 抽象類別是有範本作用的父類別,定義時在class前面要加上abstract這個保留字,繼承它的子類別一定要依照它的格式來定義。而在抽象類別(老板構想)內會有「抽象方法」成員,該方法沒有實作,其實作的敘述交由子類別(研發部間)來定義。因此抽象類別不能使用new來產生物件實體,只能被繼承。抽象類別在用class定義前,要先加上abstract關鍵字。 語法: ```java= abstract class 類別名稱{ 資料成員; 修飾子 abstract 傳回值型別 抽象方法名稱([引數串列]); //抽象方法 一般方法([引數串列]){ //一般方法 . . (敘述區段) . } } ``` 定義抽象類別,有下列幾點注意事項: :::warning 1. 抽象類別內的方法成員,可以是一般的方法成員,但最主要的是可以有「抽象方法」成員。 2. 一般方法成員內有敘述區段,而抽象方法成員只有一行宣告敘述,並用「;」做結尾,方法內沒有敘述。 3. 抽象方法必須用abstract關鍵字宣告,其修飾子不能為private,因子類別繼承時需要有權限。 4. 抽象類別被子類別繼承後,其抽象方法必須被子類別覆寫(override)。即子類別必須重新定義該抽象方法,且方法內要有實作敘述區段,如此抽象方法方能具體化。 5. 抽象類別無法建立物件實體,其建構式與一般方法成員若要由子類別來呼叫,則須使用super敘述來呼叫。 ::: > [color=#ce5112]練習 > ![](https://i.imgur.com/DQJp0ca.png) --- ## 三、介面 ### (1) 介面和類別的不同 介面和抽象類別十分相似,但還是有一些不同處,大致上來說有下列四點: 1. ==資料成員與方法成員的不同== 抽象類別的內容一定要有一個或是一個以上的抽象方法,不過卻還是允許一般的方法(有完整的敘述區段)被定義在類別內。但是介面裡面卻不可以有任何方法被完整的描述,也就是說介面就好像抽象方法一樣。介面內所宣告的方法在編譯時會變成public及abstruct的型態,因此類別實作介面方法時必須將實作的方法宣告為public的型態。而介面內所定義的變數在編譯時會變成public及final的型態,因此介面的變數為常數型態。 2. ==實作和繼承的不同== 一般而言,子類別只可繼承自一個父類別,但是一個類別卻可實作(Implement)自很多個介面。請注意這裡是指實作,而不是繼承。因一個子類別可以有多個父類別的特質,但是因為類別的繼承是不可能辦到,所以改成為一個子類別可以有多個介面的特質。 3. ==階層關係的不同== 介面和類別是不同階層的,所以不同階層的類別卻可以實作相同介面。譬如,在繼承的觀念中,基礎類別(最上層的類別)不會回過頭來繼承父類別,只有子類別會繼承父類別。不過在介面中卻不是這樣子的,不管類別是什麼關係(基礎、父、子…),都可以實作同一個介面。 4. ==效率的不同== 介面因為屬於執行時期的動態查詢,所以比較沒有效率,這和類別是不一樣的。如果程式大量地使用介面的話,將會造成較差的執行效率,所以必須謹慎使用。 ![](https://i.imgur.com/Rr4IDQn.png) --- ### (2) 介面和類別的不同 定義介面的時候,必須使用保留字interface,宣告方法成員,方法內的主體絕對是空的程式碼,而資料成員則必須給予初值,語法: ![](https://i.imgur.com/b8fdEeI.png) 如:定義 Imove介面,含有引擎數(ENGINE_NUM)資料成員和宣告addSpeed()方法成員。 ```java= interface IMove { //IMove介面 public int ENGINE_NUM = 1; //引擎數介面常數 public void addSpeed(int s); //只宣告介面的方法,無程式碼 } ``` 當介面定義好之後,可以讓其它的類別來實作。其它類別想要達到實作介面的目的必須使用implements保留字,語法: ```java= class 類別名稱 implements 介面名稱1, 介面名稱2, ...{ . . 敘述區段 . } ``` 如:PiliCar類別實作IMove介面,含有speed時速資料成員,和實作IMove介面的addSpeed()方法 (即撰寫方法內的程式碼)。寫法: ```java= class PiliCar implements IMove { //PiliCar類別實作IMove介面 private int speed; public void addSpeed(int s) { //實作IMove介面的addSpeed方法內 . . . } } ``` > [color=#ce5112]練習 > ![](https://i.imgur.com/7TakeG5.png) --- ### (3) 介面繼承 介面也提供像類別一樣的繼承機制,和類別繼承一樣是使用保留字extends,那麼介面也可以有父介面、子介面的關係存在。實作介面的類別就必須負責完成該介面及較上層介面的實作。譬如IAnimal介面繼承了IMove和IFly介面,其寫法: ```java= interface IAnimal extends IMove, Ifly; ``` > [color=#ce5112]練習 > ![](https://i.imgur.com/cPqaaZX.png) --- ## 四、多型 ### (1) 以抽象類別實作多型 「多型」(Polymorphism)是不同物件執行相同名稱的方法,卻可以得到不同的結果。因此程式在執行時會根據不同的物件自行選擇適當的方法來執行。例如:不同的形狀其面積計算公式不同。如果是三角形,其面積為 (底 * 高) / 2;如果是矩形,其面積為 長 * 寬 …。在Java中如果要達成多型,可以使用==抽象方法和介面==的方式來實作。 > [color=#ce5112]練習 > ![](https://i.imgur.com/BXym4Z7.png) --- ### (2) 以介面實作多型 當某一個子類別已經繼承了父類別,該子類別即無法再繼承抽象類別(Java是單一繼承)來達成多型,因此我們就必須使用介面來達成多型,透過介面來達成多型的寫法和抽象類別大同小異。 > [color=#ce5112]練習 > ![](https://i.imgur.com/YwCdGqn.png) --- ## 五、套件 ### (1) 套件的功能 套件除了解決名字的衝突問題之外,它還可以有效地將類別分門別類,也就是說將同一類型的類別集中在一起管理。 套件是以階層性的方式來控管,因此整體架構十分清楚。比如說您要買一部車,當您要準確地告訴業務員您要是那個廠牌那類型的車,您可以說:「福特的轎車」(因為車種包含轎車、卡車、小貨車…等),相信這樣子業務員就可以有效地為您介紹這部車。將上述例子轉成程式設計的觀念,則車子是個套件,而福特是在車子內的套件,以此類推。而轎車是個類別,以Java的語法來表示這個類別和套件的關係就是:「車子.福特.轎車」,撰寫程式時,用點符號來建立起之間的連結關係。接下來將一步一步地介紹如何撰寫套件的程式,並且學會如何管理這些套件及所包含的類別。 --- ### (2) 套件的定義 在Java中要定義套件,必須使用保留字package,而且在程式碼檔案內的第一行就要寫上去了。如此一來,所有在這個檔案(附檔名為java)內的類別都算是這個套件所擁有的,因此一個檔案只能定義一個套件名稱。其語法如下: ```java= package 套件名稱; ``` 舉個例子,如果在某個檔案(附檔名為java)內的第一行鍵入:package firstpackage的話,那麼就是建立了一個名稱為firstpackage的套件了,而這檔案內所有的類別都屬於firstpackage套件的。上面這種是最簡單的定義方式,因為Java對於套件可以階層式實作,因此當我們開發一套相當大的程式時,也許單層套件是不夠,為了能夠分門別類別的管理,就要階層式的定義,定義的格式如下: ```java= package 套件名稱1.套件名稱2…; ``` 比如說現在為A.java及B.java定義了個套件。A.java屬於firstpackage套件底下的small套件;B.java屬於firstpackage套件底下的big套件,其寫法如下: ```java= package firstpackage.small; //A.java定義為firstpackage.small套件 package firstpackage.big; //B.java定義為firstpackage.big套件 ``` 如果定義好套件時,這些檔案要如何安置。就上例而言,有了名稱為firstpackage的套件,那麼您就必須有一個名稱為firstpackage的資料夾,然後屬於firstpackage的類別,它們各自的*.class檔案都必須放在這個firstpackage資料夾裡面。因此也就是說一個套件裡不但可以有很多個類別,而且這些類別還可能是分別被撰寫在不同的*.java檔案裡頭。這也符合了之前提到的,套件為何能夠使程式設計師有效地分類那麼多類別的原因了!利用下面這張圖來做為套件結構的說明: ![](https://i.imgur.com/5L8IgIO.png) 不論類別是在那些 * .java檔案內,只要是屬於firstpackage套件的類別,就都要放在firstpackage資料夾下,要注意的是一個原始程式檔只能定義一個套件名稱。 --- ### (3)類別與類別中成員權限的設定 現在要來介紹的是類別與類別中成員(資料和方法兩者)的一些存取修飾子,為什麼在這裡說明的原因是為了要讓您先知道套件的觀念之後,這樣才能知道這些存取修飾子的功用。類別可以設定存取修飾子只有public和預設階層(也就是不宣告),若宣告類別為public表示該類別可以在不同套件做存取;若類別為預設階層表示該類別只能在相同套件做存取。 而預設、public、private、protected存取修飾子可以用來控制成員被存取的權限,這個權限用來決定成員是否可以被繼承(也就是存取修飾子使得父類別被繼承時,不見得所有的資料成員和方法成員都會被子類別所繼承)或者是否可使用。關於權限我們將它區分成兩大類來說明: ![](https://i.imgur.com/uf1SBje.png) 上表中同一套件各存取修飾子的存取權限說明如下: :::warning 1. 不宣告(預設):成員除了可以藉由類別之間的繼承關係而直接讓子類別使用,也可以經由其它類別先產生物件,再藉由物件使用。 2. public:成員除了可以藉由類別之間的繼承關係而直接讓子類別使用,也可以經由其它類別先產生物件,再藉由物件使用。 3. protected:成員除了可以藉由類別之間的繼承關係而直接讓子類別使用,也可以經由其它類別先產生物件,再藉由物件使用。 4. private:除了擁有該private成員的自身類別之外,其它類別都不能使用。 ::: ![](https://i.imgur.com/zJY0Gnd.png) 上表中不同套件各存取修飾子的存取權限說明如下: :::warning 1. 不宣告(預設):除了自身套件的類別之外,不同套件的類別都不能使用。 2. public:成員除了可以藉由類別之間的繼承關係而直接讓子類別使用,也可以經由其它自身套件或不同套件之類別產生的物件使用。 3. protected:成員可以藉由類別之間的繼承關係而使用讓子類別使用,但是不可以由不同套件之類別所產生的物件使用。 4. private:除了擁有該private成員的自身類別之外,其它類別都不能使用。 ::: --- ### (4) 引用套件 當在套件內定義好類別之後,那該如何引用某個套件下的類別呢?在Java可使用保留字import來引用指定套件下的類別。其寫法如下: ```java= import 套件名稱1.套件名稱2.…類別名稱(*); ``` 利用import保留字就可以輸入想要用的套件中的類別,而且不只可以import一次,您可以依需要import 多個套件的類別。 :::info EX. 有otherPackage、selfPackage兩個套件,其中otherPackage套件內有other類別;selfPackage套件內有Another 類別與self主程式類別。在other類別與Another 類別中皆有定義show_a、show_b、show_c、show_d四個方法,這四個方法的存取權限依序為預設、public、protected、private。 ::: > [color=#ce5112]練習 > ![](https://i.imgur.com/TExoYUf.png) ![](https://i.imgur.com/mUP4KxX.png) ![](https://i.imgur.com/MnjPKtA.png) --- # 例外處理 ## 一、例外 例外(Exception)是一種不正常的情形,該錯誤不是發生在程式編譯階段而是發生在程式執行階段。在編譯階段會發生的錯誤一般會是語法的錯誤,而發生在執行階段的錯誤統稱為例外。在程式執行時發生的不正常狀況(例外),一般常見的有下列幾種: 1. 程式執行所要開啟的檔案不存在。 2. 所載入的檔案找不到或是格式不對。 3. 存取陣列時,超出陣列元素的索引範圍。 4. 數學運算時,除數為零。 如果例外的狀況沒有事先預防,或都沒有做適當的處理,程式可能會中止,或者產生不正確的結果而狀態會一直持續下去,造成愈來愈多的不正常情形。 > [color=#ce5112]練習 > ![](https://i.imgur.com/Fdu020G.png) --- ## 二、例外處理 在Java中我們可以使用處理例外的方式,來解決程式執行階段所發生的錯誤,並在可能發生錯誤的程式區塊預先使用try敘述來檢查,再用catch敘述來捕捉錯誤的例外內容。必要時,還可加入finally敘述來補充說明或關閉資源。 ### (1) try… catch… 當例外情形發生時,為了讓產生例外的程式不中斷,而且能夠繼續往下執行,並同時將造成錯誤的例外攔截下來,建立相對的錯誤處理程式,進行補救。在Java中使用try… catch… 敘述來解決例外處理,其語法如下: ```java= try{ . . //檢查是否發生例外的程式區塊 . } catch(例外類別變數名稱){ . . //例外發生時執行的敘述區塊 . } ``` 由try... 敘述所包圍的程式區塊內容,是可能會發生例外情況的程式區塊,如:檢查除數是否為零(除數不可為0),或指定資料給陣列索引超過範圍…等例外情形的檢查。catch... 敘述的小括號內是例外的類別,當然這個例外類別是與try... 敘述內程式區塊所要檢查的例外情形是相同的。當try程式區塊內發生了例外情形時,接下來搜尋有沒有這種類型的catch程式區塊,若有找到則執行該程式區塊內的後續處理。用前一個簡例為例:我們將所發生的例外情況改用try…catch...的方式,來處理超出陣列範圍所產生的ArrayIndexOutOfBoundsException例外。如下圖表示: ![](https://i.imgur.com/iOGZ8wE.png) > [color=#ce5112]練習(使用ArrayIndexOutOfBoundsException類別來捕捉==超出陣列索引==所發生的例外) > ![](https://i.imgur.com/pipcBWy.png) > [color=#ce5112]練習(使用ArithmeticException類別來捕捉==算術運算==所發生的例外) > ![](https://i.imgur.com/7sip7Zq.png) --- ### (2) 多個catch敘述 在某些情況下,一段程式碼會發生兩個以上的例外,也就是在try程式區塊中所要檢驗的程式敘述可能發生的例外情形不止一種。要處理這情形同樣是使用try…catch…的方式,我們可使用兩個或更多個catch來檢查不同型態的例外情形,即一個try配合多個catch程式區塊的情形。當其中一個例外發生時,符合例外情況的catch…敘述就會接收執行,而其他的catch…敘述就會被跳過,繼續執行try…catch…程式區塊後面的程式碼。 > [color=#ce5112]練習 > ![](https://i.imgur.com/o3xpNDb.png) 因為在Java中例外都是由Exception類別繼承而來的,因此使用 catch (Exception e) {…} 也可以捕捉到陣列索引超出範圍、算術運算…等其它所有的例外情形。但要注意的是:==若要使用catch(Exception e){…}來捕捉例外一定要放在try的最後一個catch的敘述區塊==,否則程式編譯時會出現例外已經可以捕捉的訊息,結果發生程式無法編譯的情形。 > [color=#ce5112]練習 > ![](https://i.imgur.com/THGrodr.png) --- ### (3) try… catch… finally… 例外處理有時也會加上finally程式區塊,它會在try…catch…程式區塊完成之後執行,不管是否有符合的catch例外情況發生,finally程式區塊都會被執行。finally是一種選項,不一定每個try… catch… 都一定要有finally程式區塊,視實際程式需求而定。與try… catch … finally…一起使用的語法結構如下: ```java= try{ . . //檢查是否發生例外的程式區塊 . } catch(例外類別變數名稱){ . . //例外發生時執行的敘述區塊 . } finally{ . . //絕對會執行的程式區塊 . } ``` > [color=#ce5112]練習 > ![](https://i.imgur.com/EexGI9V.png) --- ### (4) 方法的例外處理 之前所介紹的例外發生情形,都是在main()方法所發生,如果例外是發生在所呼叫的方法(method)中時,例外會如何處理?若在所呼叫的方法內找不到可以相對應的catch程式區塊的話,系統會自動回到它的上一層方法當中去尋找符合的catch程式區塊?我們舉一個實際的程式範例來說明: > [color=#ce5112]練習 > ![](https://i.imgur.com/AJTWJIb.png) ![](https://i.imgur.com/vsHbNFR.png) --- ## 三、Java常用的內建例外類別 所有的例外類別都是內建類別Throwable的子類別。Throwable是例外類別中的最上層,由它延伸出Error類別和Exception類別。在本章我們所討論都是屬於Throwable類別下的Exception子類別。從Exception類別又可以再延伸出RuntimeException類別,RuntimeException類別屬於執行時期時所發生的例外情形。例如前面範例的ArrayIndexOutOfBoundsException是發生的陣列超出索引的例外情形,就是屬於RuntimeException這個類別所衍生出來的子類別。下表是RuntimeException的子類別,這也是Java中常使用的內建例外類別: ![](https://i.imgur.com/wFiGxcA.png) :::info Ex. 使用者由鍵盤輸入兩個整數數值進行除法運算,在輸入數值的過程,使用try… catch…敘述來偵測可能會因輸入資料格式不符所引發的例外。 ::: 備註: ```java= Integer.parseInt(String s) 方法:解析字符串參數s為有符號十進製整數。 nextLine():取得使用者輸入的字串(包含空白字元、空白鍵、Tab) ``` > [color=#ce5112]練習 > ![](https://i.imgur.com/gWKhnr8.png) --- > [color=#ce5112]執行:正確輸入 > ![](https://i.imgur.com/VY0aP8K.png) --- > [color=#ce5112]執行:除數為0 > ![](https://i.imgur.com/tfMHbBC.png) --- > [color=#ce5112]執行:輸入字串 > ![](https://i.imgur.com/7WgvhKL.png) --- ## 四、自行拋出例外 前一節的範例所產生的例外類別,如:ArrayIndexOutOfBoundsException、ArithmeticException、NumberFormatException…等,這些例外都是Java虛擬機器(簡稱JVM)執行時產生的。當程式在執行階段發生例外,預設的情況下,例外會被 JVM攔截並拋出,再用try…catch…finally…處理。有些類別的方法,可能因為傳進來的引數錯誤,或是其他特殊不可預測的錯誤情形,導致程式無法繼續下去,此時需要使用自行拋出(throw)例外的技巧。本節所介紹自行拋出例外的方式有兩種,如下: 1. 在程式碼的敘述中,使用throw拋出例外。 2. 在定義方法時,使用throws宣告該方法可以拋出的例外。 --- ### (1) 使用throw 所有的例外型別都是內建類別Throwable的子類別,而使用throw可以拋出一個例外的物件實體,這個物件必須是Throwable類別的物件,或是Throwable子類別的物件。當使用throw拋出例外後,接在throw之後的敘述將不會執行,會由catch來補捉所符合的例外。 > [color=#ce5112]練習 > ![](https://i.imgur.com/JSEoedp.png) --- ### (2) 使用throws 可以使用throws敘述,來宣告某個方法可能發生的例外。當例外發生時,再使用throw敘述拋出方法會產生的例外物件,接著會返回呼叫這個方法的程式。若方法可能產生的例外類型不只一種時,只要將可能產生的例外類型都寫到throws敘述中,每個例外類型之間使用逗號隔開即可。 備註: ```java= (int) //如數字為小數,會強制轉為整數 ``` > [color=#ce5112]練習 > ![](https://i.imgur.com/L3AKUyE.png) --- ## 五、自定例外類別 在Java中所內建的例外類別是在程式設計過程較容易出現的例外,已能處理大部份的例外問題,但在處理某些特殊的例外情況時,內建的例外類別是無法滿足我們的需求的。因此,Java也允許建立自己的例外型別,讓我們可以用來處理應用程式中的特殊情況。 自定例外的做法其實很簡單,只要將自行定義的類別繼承Exception類別或衍生出來的類別即可,所有的例外類別(包含Exception)都是內建類別Throwable繼承而來的,Exception類別並沒有定義屬於自己的方法,因此當繼承Exception類別後,您可以覆寫Throwable類別的方法成員並定義自己所需要的例外訊息。下表為Throwable常用的方法成員: ![](https://i.imgur.com/GJDMvSZ.png) Java自定例外類別後,然後在程式敘述中再使用throw拋出自定例外類別的例外物件。語法結構如下: ```java= class 自定例外類別 extends 例外類別{ . . //程式敘述區段 . } . . . throw 自定例外類別物件; . . . ``` 自定例外類別必須繼承系統預設例外類別(如:Exception),或是衍生出來的例外類別(如:NumberFormatException)。 :::info Ex: 自定一個例外類別,防止員工的薪水設定超過100000。使用自己定義的MyException例外類別,當輸入的薪水超過100000時,MyException例外情形就會被觸發。 ::: > [color=#ce5112]練習 > ![](https://i.imgur.com/qlfOaqs.png) --- # 集合與泛型 ## 一、集合物件 集合物件和陣列類似。陣列是將一群資料型別相同的資料收集在一起。集合物件是收集一群相關資料,將資料稱為元素。以特定集合類別如:Hashtable、TreeSet、ArrayList、LinkedList、HashMap、TreeMap 來處理或存取這些資料。此技術可用陣列排序、搜尋演算法達到同樣處理結果。==程式敘述涉及資料結構,程式複雜度高,可改用 集合物件 直接處理群聚資料的特定存取==。 ### (1) Collections Framework 架構 Java 的 ==java.util.* 套件==提供五組集合介面和可實作的具體類別。不同集合類別產生不同集合物件。集合物件有很多種,其中元素的資料: - 有些可重複出現 - 有些可自動排序 - 有些需鍵值對應 為使這些集合類別能較有一致性,Java 提供一套架構稱為 Java Collections Framework。 組成方式: 1. **集合介面** 各集合相關介面:Collection、Set、SortedSet、List、Map、SortedMap 分兩個體系: ![](https://i.imgur.com/Fvs9hpY.png) 2. **實作集合介面的具體類別** 介面只定義抽象方法沒實作內容。各集合介面皆有對應集合具體實作類別,這些集合類別可用 ==new 來建立集合物件==。下表為集合介面與對應具體實作類別: ![](https://i.imgur.com/FwLuuwG.png) --- ### (2) 集合物件的特性 元素間因關係需求不同而存放在不同集合物件內不同實作集合介面的類別所建立的集合物件有不同的特性。不同特性共四種: :::warning 1. 排序性 2. 循序性 3. 唯一性 4. 鍵值對應 ::: --- ### (3) 泛型型別與集合物件 集合物件中的元素可儲存不同型別的資料:當取出元素資料須先知集合物件中各元素 的==資料型別==。再==轉換成適用型別==,執行時也易出錯。若用具樣版性質的 泛型型別來儲存集合物件 的資料,可省去元素資料型別轉換並避免執行時出錯。==建立集合物件時以泛型型別標明元素要存放的資料型別==。如: ```java= 集合具體實作類別名稱<E>集合物件名稱 = new 集合實作類別名稱<E>(); ``` --- 例如:由能==具體實作Set介面==的==集合類別HashSet==建立的==集合物件hset==,若要存放Integer資料的話,其建立集合物件時的程式碼有下列二種方式: ```java= 1. HashSet<Integer> hset = new HashSet<>(); 2. Set<Integer> hset = new HashSet<>(); ``` --- 例如:由能==具體實作SortedSet介面==的==集合類別TreeSet==建立的==集合物件tset==,若要存放String資料的話,其建立集合物件時的程式碼有下列二種方式: ```java= 1. TreeSet<String> tset = new TreeSet<>(); 2. SortedSet<String> tset = new TreeSet<>(); ``` --- 但是,若想要建立的集合物件==沒有指定存放的資料型別==時,可使用==var==來宣告,此時集合物件所存放的==資料型別為Object==,其建立集合物件時的程式碼如下: ```java= var hset = new HashSet<>(); var tset = new TreeSet<>(); ``` --- ## 二、Collection&lt;E&gt;介面 Collection&lt;E&gt; 介面是最上層介面它==沒集合類別直接實作==,可藉由子介面 Set&lt;E&gt;、List&lt;E&gt; 或SortedSet&lt;E&gt; ==具體類別間接實作來建立集合物件==。該物件只能實作 Collection&lt;E&gt; 介面的方法。類別 HashSet 能具體實作 Set介面欲建立 集合物件hset,宣告和建立方式: ```java= HashSet<Integer> hset = new HashSet<>(); ``` --- Collection&lt;E&gt; 介面為 Set&lt;E&gt;介面的父介面也可由 Set 介面的具體類別 HashSet 來實作。程式碼可改成: ```java= Collection<Integer> hset = new HashSet<>(); ``` 在Java中,Collection 介面用 Collection&lt;E&gt;表示,&lt;E&gt;為泛型型別。Collection 介面常用方法: :::warning 1. boolean isEmpty() 如集合物件是空沒任何元素傳回 true。 2. boolean add (E e) 將引數中的 物件e 新增為元素。新增成功,傳回 true;新增失敗,傳回 false。 3. boolean addAll (Collection&lt;? Extends E&gt; c) 將引數中的 Collection&lt;E&gt;集合物件c 所有元素都新增為這個Set&lt;E&gt;介面集合物件的元素。若新增成功傳回 true。 4. int size() 傳回集合物件的元素個數。 5. boolean contains(Object o) 如集合物件中包含指定o的元素,傳回 true。 6. boolean containsAll(Collection&lt;?&gt; c) 如集合物件中包含指定 Collection&lt;E&gt;集合物件c 的所有元素,傳回 true。 7. boolean remove(Object o) 若集合物件中存在指定o的元素,則將其移除。移除成功,傳回 true。 8. boolean removeAll(Collection&lt;?&gt; c) 移除存在集合物件中指定Collection&lt;E&gt;集合物件c 的所有元素。全部元素移除成功傳回true。 9. boolean retainAll(Collection&lt;?&gt; c) 在集合物件中僅保留所指定Collection&lt;E&gt;集合物件c的元素,其餘皆移除。若成功傳回true。 10. void clear() 移除集合物件中的所有元素。 11. boolean equals(Object o) 比較指定的物件o與本集合物件的相等性。如指定物件o也是一個集合物件,且與本集合物件大小相同,且所有成員都包含其中,傳回true。 ::: --- ## 三、Set&lt;E&gt;介面與HashSet&lt;E&gt;類別 HashSetn&lt;En&gt; 類別常用建構式: :::warning 1. **HashSet()** 建立一個全新的空HashSet集合物件,預設元素個數為16個。 2. **HashSet(Collection&lt;? Extends E&gt; c)** 建立一個含指定Collection&lt;E&gt; 介面物件c 的HashSet 集合物件。 3. **HashSet(int i)** 建立一個全新的空HashSet物件,並經由引數I來指定元素個數。 ::: 假設集合類別建立的集合物件實體名稱為hset,可以使用==hset.add==()方法來存放資料,或使用==hset.remove==()方法來移除資料。因此這種集合物件是「==動態集合==」。但==Set介面可建立「靜態集合」==,該集合建立時就決定元素的內容及元素個數。如下: ```java= var number = Set.of(23, -76, 54, 89, 34, 0, -55, -27, 61); ``` 或 ```java= var word = Set.of(“We”, “very”, “love”, “Java”); ``` 但是Set介面建立的靜態集合,其元素的資料型別為Object,而且==元素內容不能重複==。 > [color=#ce5112]練習 > ![](https://i.imgur.com/85IorA1.png) **(印出的順序為隨機排序,英文也是)** --- ## 四、SortedSet&lt;E&gt;介面與TreeSet&lt;E&gt;類別 Set&lt;E&gt; 介面繼承最上層Collection &lt;E&gt;介面規範實作 Set&lt;E&gt;介面 的集合物件的元素資料不能重複,但資料沒排序。Set&lt;E&gt;介面又被 SortedSet&lt;E&gt;介面繼承,Java用TreeSet 類別實作 SortedSet&lt;E&gt;介面,所建集合物件的==元素資料不會重複==,還==主動進行自然排序==。 ### (1) TreeSet&lt;E&gt;類別 TreeSet&lt;E&gt;類別常用的建構式: :::warning 1. TreeSet() 2. TreeSet(Collection&lt;? Extends E&gt; c) 3. TreeSet(SortedSet&lt;? Extends E&gt; s) ::: ### (2) SortedSet&lt;E&gt;介面 SortedSet&lt;E&gt; 介面繼承 Set&lt;E&gt; 介面, 可同時繼承 Set&lt;E&gt;介面的方法成員。 列出 SortedSet&lt;E&gt;介面新增且常用的方法成員: :::warning 1. E first() : 返回此集合中的第一個元素。其中,E 表示集合中元素的資料型別。 2. E last() : 返回此集合中的最後一個元素 3. SortedSet&lt;E&gt; headSet(E toElement) : 返回一個新的集合,新集合包含原集合中 toElement 物件之前的所有物件。不包含 toElement 物件。 4. SortedSet&lt;E&gt; tailSet(E fromElement) : 返回一個新的集合,新集合包含原集合中 fromElement 物件之後的所有對象。包含 fromElement 物件。 5. SortedSet&lt;E&gt; subSet(E fromElement, E toElement) : 返回一個新的集合,新集合包含原集合中 fromElement 物件與 toElement物件之間的所有物件。包含 fromElemen t物件,不包含 toElement 物件。 ::: > [color=#ce5112]練習 > ![](https://i.imgur.com/BRbXsD3.png) 備註:[[參考資料]](http://tw.gitbook.net/java/util/treeset_tailset.html) ```java= public SortedSet<E>.tailSet(E fromElement); //找出集合物件中,大於等於(E fromElement)的數 ``` --- ## 五、List&lt;E&gt;介面與實作類別 List&lt;E&gt; 介面能==建立序列的集合物件==,每個元素皆有精確==索引位置==來擺放,根據元素所在列表索引位置存取或搜尋元素資料。List&lt;E&gt; 介面與 Set&lt;E&gt; 介面都繼承Collection&lt;E&gt; 介面,Set&lt;E&gt; 介面強調集合物件之儲存元素的資料不能重複。本節介紹的 ==List&lt;E&gt; 介面的集合物件,元素資料是可重複==。 List&lt;E&gt;介面與SortedSet&lt;E&gt;介面所建立集合物件不同。SortedSet&lt;E&gt;介面是建立排序性的集合物件,資料順序根據元素大小由小到大排列。List&lt;E&gt;介面是建立==循序性==的集合物件,資料順序是根據元素列表索引值位置一個接一個排列,==索引值依序為0、1、2、3…==。 ### (1) List&lt;E&gt;介面 List&lt;E&gt; 介面常用方法: :::warning 1. boolean add(E e) : 向集合中新增一個元素,E 是元素的資料型別。 2. void add(int index, E element) 3. boolean addAll(Collection&lt;? Extends E&gt; c) : 向集合中新增集合 c 中的所有元素。 4. boolean addAll(int index, Collection&lt;? Extends E&gt; c) 5. E get(int index) : 獲取此集合中指定索引位置的元素,E 為集合中元素的資料型別。 6. int indexOf(Object o) : 返回此集合中第一次出現指定元素的索引,如果此集合不包含該元素,則返回 -1。 7. int lastindexOf(Object o) : 返回此集合中最後一次出現指定元素的索引,如果此集合不包含該元素,則返回 -1。 8. E remove(int index) 9. E set(int index, E element) : 將此集合中指定索引位置的元素修改為 element 引數指定的物件。此方法返回此集合中指定索引位置的原元素。 10. ListE subList(int fromIndex, int toIndex) : 返回一個新的集合,新集合中包含 fromlndex 和 tolndex 索引之間的所有元素。包含 fromlndex 處的元素,不包含 tolndex 索引處的元素。 ::: --- ### (2)ArrayList&lt;E&gt; 類別 ==ArrayList&lt;E&gt; 陣列串列類別實作List&lt;E&gt;串列介面==,建立集合物件元素儲存方式和陣列相似,用==索引值==依序將元素加入到串列中。 List&lt;E&gt;串列,不同陣列是==不用事先宣告元素數量==。串列是一個可自行調整大小的動態陣列。 ArrayList&lt;E&gt; 類別的建構式: :::warning 1. ArrayList() 2. ArrayList(Collection&lt;? extends E&gt; c) 3. ArrayList(int i) ::: ArrayList&lt;E&gt;除擁有實作List&lt;E&gt;介面的方法成員外,也自行有增加方法成員: 1. 增加此ArrayList集合物件的容量 ==void ensureCapacity(int minCapacity)== 2. 將此 ArrayList 集合物件的容量調整為列表目前的大小==void trimToSize()== List介面也可建立「==靜態集合==」,該集合建立時就決定元素的內容及元素個數。如下: ```java= var number = List.of(23, -76, 54, -74, 23, 0, -27, 61); ``` 或 ```java= var word = Set.of(“We”, “love”, “very”, “love”, “Java”); ``` List介面建立的靜態集合,元素的==資料型別為Object==,元素內容==可以重複==。 > [color=#ce5112]練習 > ![](https://i.imgur.com/uJ5qJfP.png) --- ### (3) LinkedList&lt;E&gt;類別 ==LinkedList&lt;E&gt;鏈結串列類別用來實作List&lt;E&gt;介面==,建立集合物件之元素儲存方式是一種鏈結串列,每個元素可能散佈在記憶體不同位置。為能存取或搜尋元素資料,將每個元素視為一個節點每個節點有資料欄和鏈結欄。 資料欄存放元素資料。鏈結欄則存放指標,存放下一個節點(資料)的記憶體位址。若某一節點的指標指向null,代表該節點為集合的結尾。 ![](https://i.imgur.com/HyK0b1T.png) LinkedList&lt;E&gt; 鏈結串列類別的建構式: :::warning 1. LinkedList() 2. LinkedList(Collection&lt;?&gt;extends E> c) ::: LinkedList&lt;E&gt;類別實作List&lt;E&gt;介面在List&lt;E&gt; 方法成員皆可搬到 LinkedList&lt;E&gt;類別使用。 LinkedList&lt;E&gt;類別新增方法成員主要特性,在處理鏈結串列的集合頭尾元素: :::warning 1. void addFirst(E e) : 將指定元素新增到此集合的開頭。 2. void addLast(E e) : 將指定元素新增到此集合的末尾。 3. E removeFirst() : 刪除此集合中的第一個元素。 4. E removeLast() : 刪除此集合中的最後一個元素。 5. E getFirst() : 返回此集合的第一個元素。 6. E getLast() : 返回此集合的最後一個元素。 ::: --- ### (4) 佇列與堆疊 基於LinkedList&lt;E&gt;類別方法成員的特性,所建立出的集合物件適合實作佇列(Queue)與堆疊(Stack)。 ==佇列:是一種「先進先出」(FIFO)的資料結構== ![](https://i.imgur.com/oWdu2Dz.png) ![](https://i.imgur.com/ut1p7YP.png) ![](https://i.imgur.com/9KMo25Y.png) ![](https://i.imgur.com/oHKjxAx.png) > [color=#ce5112]練習 > ![](https://i.imgur.com/S7QAUdA.png) --- ## 六、Map<K, V>介面與 HashMap<K, V>類別 Map&lt;K, V&gt;並沒繼承Collection&lt;E&gt;介面,它自成一個獨立架構的集合介面。實作 Map&lt;K, V&gt;介面的集合物件處理集合元素,是取「==鍵值對應==」的方式。利用指定關鍵值儲存資料,每個鍵值最多只能儲存一個對應值(Value),==鍵值是唯一不能重複==,但不同關鍵值卻能有相同的對應值。 ### (1) Map&lt;K, V&gt;介面 Map&lt;K , V&gt;介面常用的方法如下: :::warning 1. boolean containsKey(Object key) 2. boolean containsValue(Object value) 3. void clear() 4. boolean isEmpty() 5. V put(K key, V value) : 向 Map 集合中新增鍵-值對,返回 key 以前對應的 value,如果沒有, 則返回 null。 6. void putAll(Map&lt;?&gt;extends K, ? extends V&gt; m) 7. V get(Object key) : 返回 Map 集合中指定鍵物件所對應的值。V 表示值的資料型別。 8. V remove(Object key) : 從 Map 集合中刪除 key 對應的鍵-值對,返回 key 對應的 value,如 果沒有,則返回null。 9. int size() 10. Set&lt;K&gt; keySet() : 返回 Map 集合中所有鍵物件的 Set 集合 11. Collection&lt;V&gt; values() ::: --- ### (2) HashMap&lt;K , V&gt;類別 HashMap&lt;K, V&gt; 物件會根據關鍵值的雜湊程式碼,==整理出關鍵值(key)與對應值(value)組配對的集合==。每個關鍵值都必須唯一且==關鍵值與對應值內容皆可為null==。 HashMap&lt;K, V&gt;類別建構式: :::warning 1. HashMap() 2. HashMap(Map&lt;? extends K, ? extends V&gt; m) 3. HashMap(int i) ::: > [color=#ce5112]練習 > ![](https://i.imgur.com/NDFRzVw.png) 備註: 1. [Map.Entry](https://docs.oracle.com/javase/8/docs/api/java/util/Map.Entry.html) 2. [entrySet()](https://www.geeksforgeeks.org/hashmap-entryset-method-in-java/) --- ## 七、SortedMap<K, V>介面與TreeMap類別 SortedMap&lt;K, V&gt;介面繼承Map&lt;K, V&gt;介面,TreeMap&lt;K, V&gt;類別,用來實作SortedMap&lt;K,V&gt;介面。用TreeMap&lt;K, V&gt;類別建立出的集合物件,也是關鍵值(key)與對應值(value)組配對集合。 不同於HashMap&lt;K, V&gt;類別集合物件的是,TreeMap&lt;K, V&gt;集合物件是==有順序集合==,其元素依關鍵值==由小到大自動排序==。 ### (1) TreeMap&lt;K, V&gt;類別 TreeMap&lt;K, V&gt; 類別常用建構式: :::warning 1. TreeMap() 2. TreeMap(Map&lt;? extends K, ? extends V&gt; m) 3. TreeMap(SortedMap&lt;K, ? extends V&gt; m) ::: ### (2) SortedMap&lt;K, V&gt;介面 SortedMap&lt;K, V&gt; 介面,繼承 Map&lt;K, V&gt;介面,同時繼承 Map&lt;K, V&gt;介面方法成員。 SortedMap &lt;K,V&gt;介面新增且常用方法成員: :::warning 1. K firstKey() 2. K lastKey() 3. SortedMap&lt;K, V&gt; headMap(K toKey) 4. SortedMap&lt;K, V&gt; tailMap(K fromKey) 5. SortedMap&lt;K, V&gt; subMap(K fromKey, K toKey) ::: > [color=#ce5112]練習 > ![](https://i.imgur.com/OJfJ7Mv.png) --- ## 八、Collections 集合工具類別 Collections==不是介面也不是集合==它是Collection介面的==工具類別==。Collections類別中的方法成員皆由 ==static定義的靜態方法==,不需先建立物件實體==可直接呼叫==使用。集合物件可用Collections工具類別提供靜態方法(類別方法)來處理集合物件內各元素的資料,如==排序、反轉元素排列順序、取最大值==。 Collections集合工具類別所提供的常用靜態方法: :::warning 1. static void sort(List&lt;T&gt; list) 2. static void reverse(List&lt;T&gt; list) 3. static void copy(List&lt;T&gt; dest, List&lt;T&gt; src) 4. static void fill(List&lt;T&gt; list, Object obj) 5. static Object max(Collection coll) 6. static Object min(Collection coll) 7. static void swap(List&lt;T&gt; list, int i, int j) ::: > [color=#ce5112]練習 > ![](https://i.imgur.com/TGTZHY5.png) --- ## 九、集合的走訪器 Java為集合物件提供兩個走訪器: - **Iterator&lt;E&gt;** - **ListIterator&lt;E&gt;** 集合走訪器是一種==介面==,功能不是用來建立集合物件,是用來走訪集合物件中的元素。所謂「走訪」是==讀取集合物件中的元素==,走訪也能刪除元素。 ### (1) Iterator&lt;E&gt;介面 能實作下圖Collection支系介面的集合物件皆可實作 Iterator&lt;E&gt;介面。利用這些介面的iterator()方法,即可取得實作Iterator&lt;E&gt;介面的物件。實作 Iterator&lt;E&gt;介面的物件除==可讀取Set、List、SortedSet 介面的集合物件==的元素資料,並可刪除指定的元素。 ![](https://i.imgur.com/dlTBAzC.png) ![](https://i.imgur.com/QoAmFYA.png) > [color=#ce5112]練習 > ![](https://i.imgur.com/2Kv8X6t.png) --- ### (2) ListIterator&lt;E&gt;介面 ListIterator&lt;E&gt;介面繼承Iterator&lt;E&gt;介面。Iterator&lt;E&gt;介面物件走訪方式是==單向==。ListIterator&lt;E&gt;介面物件走訪集合物件方式是==雙向==。Iterator&lt;E&gt;介面物件只能讀取與刪除 集合物件的指定元素ListIterator&lt;E&gt;介面物件處理集合物件有==讀取、刪除、新增、修改==。走訪 ArrayList&lt;String&gt;集合物件alist,可用 listIterator()方法取得實作 ListIterator&lt;E&gt;介面的物件 litera。 ![](https://i.imgur.com/55Z7KKc.png) ListIterator&lt;E&gt;介面的方法成員: :::warning 1. boolean hasNext() 2. boolean Previous() 3. E next() 4. E previous() 5. int nextIndex() 6. int previousIndex() 7. void add(Object o) 8. void set(Object o) 9. void remove() ::: > [color=#ce5112]練習 > ![](https://i.imgur.com/X98M886.png) --- # 多執行緒 ## 一、執行緒簡介 作業系統是一套系統軟體。是電腦系統的核心。 用來管理電腦硬體與軟體資源的程式。作業系統主要功能對一個將執行應用程式進行記憶體管理與配置。決定應用程式使用系統資源的優先次序、輸出入裝置的控制、網路連線與檔案系統管理等基本工作。將作業系統正在執行的一個應用程式稱為行程Process),系統按照需求分配系統資源與CPU Time給此 Process,當系統執行另一個應用程式時,又是另一個 Process和資源配置的產生,同時也會配置 CPU Time 給該Process。當作業系統執行應用程式時,Process 與資源是各自獨立的,應用程式間才不相互干擾。 多工 (MultiTasking) 作業系統允許兩個以上應用程式同時執行,原理是由於 CPU處理速度快,可 將 CPU Time分成多Time Slice。CPU 在某個 Time Slice 執行某個 Process時,下一個ime Slice 跳至另一個 Process去執行,由於切換速度很快,使得每個程式像是同時進行處理。可同時執行多個不同應用程式。 MultiTasking 作業系統的執行單位是 Process。Multi threading作業系統的執行單位是Thread。MultiThread與傳統的 Process 非常類似一個 Process 中可能會包含數個Threads同屬某個Process 的各 Threads 會共用某塊共同記憶體,以降低彼此間控制權轉移時的負擔,作業系統不提供保護措施,須由程式設計人員自行控制。 假設只有一顆CPU,程式雖可處理多個執行緒,但同時間點,只能有一個執行緒位於執行狀態即在CPU 執行,其他執行緒留在 Runnable 區塊中等待,下次執行輪到哪個執行緒,是由JVM執行緒的優先權處理程式來做判定。 Java 允許一個程式能同時執行兩個(含)以上執行緒。 ![](https://i.imgur.com/7hWRMgJ.png) 以前應用程式在一個行程中只能處理一件事情。現利用一個行程中可包含多個執行緒。可將程式分割成一些獨立的工作。分時來執行以達到程式多工的效果。若運用得當多執行緒可大幅提升效能,若分配不當可能比單一執行緒更沒有效率使用多執行緒時要多注意資源配置。 一般程式語言執行程式時,都是一行接一行程式碼循序來執行。Java語言是經由 JVM 來執行程式,程式執行起點是由 main()方法開始,隨程式內容來作運算、判斷、再判斷…,一直到程式結束為止。Java 程式開始執行時會有一個執行緒開始執行,此執行緒稱為程式的主執行緒。在Java 語言中允許同時有多個程式的動作一起執行,除主執行緒外,每個動作也都是一個執行緒,這也就是多執行緒的執行。 ![](https://i.imgur.com/WqDw3ed.png) 圖a –表示程式從開始執行到結束都只有一條主執行緒。 圖b - 多執行緒程式 --- ## 二、執行緒的生命週期 在 Java 中執行緒其實就是 Thread 物件。執行緒生命週期從建立一條新執行緒到消滅過程: ![](https://i.imgur.com/wRfBwa2.png) --- ## 三、如何建立執行緒 建立執行緒的方式有兩種: 1. 利用繼承自 Thread 類別的子類別直接產生執行緒。 2. 以自定類別實作 Runnable 介面間接產生執行緒。 ### (1) 繼承 Thread 類別建立執行緒 使用繼承方式建立執行緒 - 宣告子類別繼承自Thread類別且子類別中還要覆寫Thread 類別的 run()方法。 - run()方法是執行緒主體,執行緒要處理事情的程式要寫在run()方法中。 - 當呼叫 Thread 類別的 start() 方法來啟動執行緒後會執行該執行緒的run()方法。 1. 直接建立 Thread 類別執行緒物件 ![](https://i.imgur.com/B0GLTrE.png) > [color=#ce5112]練習 > ![](https://i.imgur.com/0DZJ3vC.png) --- 2. 宣告繼承自Thread類別的自定執行緒類別 ![](https://i.imgur.com/Brz67rH.png) > [color=#ce5112]練習 > ![](https://i.imgur.com/5arPwRt.png) --- ### (2) 實作Runnable介面來建立執行緒 前面採繼承Thread父類別方式來建立執行緒程式撰寫較簡單但彈性較小。如子類別同時又要 繼承其它類別時,因 Java 每個類別只能有一個父類別(單一繼承)不允許多重繼承。為解決此問 題,另提供實作 Runnable 介面。實作 Runnable 介面時,還須要實作run()方法。使用 Runnable介面所建立的新類別,只是一個準執行緒,還必須藉由準執行緒的物件來建構Thread 類別的物件用以啟動執行緒,其方式如下: ![](https://i.imgur.com/4oJC3sd.png) > [color=#ce5112]練習 > --- ## 四、Thread 類別常用的方法 ### (1) Thread類別的建構式 :::warning 1. public Thread() 2. public Thread(String name) 3. public Thread(Runnable target) 4. public Thread(Runnable target, String name) ::: ### (2) Thread 類別常用方法 :::warning 1. public final void setName(String threadName) 2. public final String getName() 3. public static Thread currentThread() 4. public static final boolean isAlive() 5. public final void setPriority() 6. public final int getPriority() 7. public static void sleep(long time) throw InterruptedException 8. public final void join() throws InterruptedException ::: > [color=#ce5112]練習 > --- > [color=#ce5112]練習 > --- ## 五、執行緒的同步 (Synchronized) 為什麼執行緒需要同步呢?理論上,Thread 物件可存取在 Java 程式中任一物件。執行緒同步主要原因是為避免在同時間點,有多個執行緒同時存取同個物件造成資料錯誤。JVM 提供一種機制,發生多個執行緒同時存取且同時修改同個物件時,利用關鍵字synchronized 來解決物件混亂情形。 做法: 當執行緒進入有用 synchronized 的程式區塊時,先檢查該區塊是否已經被鎖定(lock) ?有沒有其它Thread 物件已先進入該區塊?若沒有其它Thread物件佔住該區塊,目前Thread物件就可進入該程式區塊,同時將程式塊區鎖定以避免其它 Thread物件進入。若程式區塊已被其它 Thread 物件鎖定,Thread 物件會進入中斷 態,繼續等待被鎖定程式區塊被釋放。 ![](https://i.imgur.com/KFqeMfu.png) > [color=#ce5112]練習 > --- > [color=#ce5112]練習 > --- ## 六、執行緒的等待和喚醒 Object 物件中提供 :wait()、notify() 和 notifyAll() 方法,可讓執行緒間相互設定等待和喚醒。 :::warning 1. wait(): 讓指定執行緒進入Wait pool 成為等待狀態,每個物件都有自己專有Wait pool。 2. notify(): 喚醒一個在Wait pool等待執行緒,哪個執行緒被喚醒由 JVM 決定。 3. notifyAll(): 喚醒所有在 Wait pool等待執行緒,至於是哪個執行緒會先執行仍是由JVM決定。 ::: > [color=#ce5112]練習 > --- # Lambda ## 一、Lambda簡介 Lambda語法是Java 8開始提供的新功能,此語法並不是新的語法,在Script 語言和Functional語言中都可以見到,像C#及VB也都有提供Lambda語法。在不同領域,對於Lambda的定義可能不太一樣,但相同的是Lambda可當成一個方法,可依不同輸入值,來傳回輸出值。Lambda與一般方法不同是,Lambda不需要替方法命名,Lambda常用於匿名(Anonymous)類別並實作方法的場合上,以便讓Java語法更簡潔。 --- ## 二、Lambda簡例介紹 Lambda語法通常用於只有一個public方法的介面。 ### (1) 以執行緒為例 建立執行緒物件,並將目前的執行緒印10次,且採用實作Runnable介面的方式來建立執行緒。 ![](https://i.imgur.com/sXee0am.png) > [color=#ce5112]練習 > ![](https://i.imgur.com/qHg1aes.png) --- > [color=#ce5112]練習(Java SE 8 之前的簡化語法) > ![](https://i.imgur.com/6C34s9C.png) --- 使用Lambda簡化程式碼,請比較修改前和修改後(使用Lambda)的差異: ![](https://i.imgur.com/MzqGuRA.png) Lambda不需要替方法命名,可用於==匿名==(Anonymous)類別並實作方法的場合上,以便讓Java語法更簡潔。 > [color=#ce5112]練習 > ![](https://i.imgur.com/PoclldV.png) --- ### (2) 以自定類別物件為例 使用==Arrays.sort()方法==配合==Comparator介面==來排序Product自行定義的產品類別。Product產品類別內含name、price、qty等品名、單價、數量的私有成員;以及用來傳回該產品單價乘數量的銷售金額的==getTotal()公開方法==;以及用來顯示產品品名、單價、數量以及銷售金額資訊的==show()公開方法==。 ![](https://i.imgur.com/lM8MUGx.png) > [color=#ce5112]練習 > ![](https://i.imgur.com/mdHhI7k.png) --- > [color=#ce5112]練習(Java SE 8 之前語法) > ![](https://i.imgur.com/Ce14Ezw.png) --- > [color=#ce5112]練習(Lambda) > ![](https://i.imgur.com/NX5VZsG.png) --- ## 三、Lambda語法說明 ### (1) Lambda語法結構 Lambda可以當成是一個沒有方法名稱的方法。如下語法,input代表的是方法的引數;->之後的body是方法的程式碼主體,若方法內的程式碼主體只有一行則左大括號 { 和右大括號 }可以省略。 (input) -> { body } ![](https://i.imgur.com/VAi5UH1.png) ![](https://i.imgur.com/SN0JlO9.png) ![](https://i.imgur.com/Z3zeN5r.png) ![](https://i.imgur.com/lnzNqlE.png) --- ### (2) Lambda應用與效能 ![](https://i.imgur.com/eCQDoAp.png) --- ## 四、方法參考 Lambda還有另一項優點,就是重用Java API現有的方法,重用現有方法,就是Java 8「方法參考」(Method reference)的特性。想要使用Arrays.sort()方法來排序name姓名字串陣列,預設排序方式是依英文大小寫來進行排序,下例希望排序時忽略英文大小寫,因此在Arrays.sort()方法第二個引數撰寫了Lambda運算式,在Lambda運算式中實作了字串排序規則,排序規則使用字串比較方法compareTo IgnoreCase(),此方法比較字串會忽略英文大小寫。 > [color=#ce5112]練習 > ![](https://i.imgur.com/DXAUQnv.png) --- ![](https://i.imgur.com/djBDvH5.png) > [color=#ce5112]練習 > ![](https://i.imgur.com/NDo7E4l.png) --- > [color=#ce5112]練習 > ---