###### tags: `Java Tutorial` # Java筆記 `Creater: AluoExpiry` `Co Writer: Miyago9267` `Last Updater: AluoExpiry` `Created Time: 2020-10-09 01:39:16` `Updated Time: 2024-10-10 12:55:45` ## 起手式 ```java= public class ClassName{ public static void main(String args[]) { } } ``` > 包裹`main()`的函式的`ClassName`請務必與檔名相同 > 例如`Main.java`,`ClassName`就是`Main` ## 變數 ### 變數宣告 - `int` : 整數型態(integer) - `float` : 單精度浮點型態 - `long` : 長整數型態 - `double` : 雙精度浮點型態 - `char` : 字元,以''表示 - `String` : 字串,以""表示 :::info 宣告方式為 : **型態 變數名稱;** ::: ex: ```java= int i; String s; float f; ``` 除字串外,其餘型態皆可於宣告時給定初值 ex: ```java= int i = 0; float tt = 0.0f; //f很重要,用意是告訴系統這個值是float型態 double dou = 0.123; ``` ### 輸出 ```java= System.out.print() //輸出文字且不換行 System.out.println() //輸出文字且換行 System.out.printf() //輸出文字且自動帶入參數 ``` > [Java中printf用法](https://www.itread01.com/content/1510988643.html) ### 賦予值 / 給定值 在Java中,將某個設定給變數是用「=」,以下為範例 ```java= int a, b, c; String str; a = 10; b = 12; c = a + b; str = "Hello, world!"; ``` 以c = a + b為例,「=」的作用是將a + b的結果設定給c,也就是給定值 ### 運算 運算大致分成以下三大類: #### 算術運算 算術運算即是常見的四則運算以及平方等數學運算,常用運算子如下: ``` 加法 => + 減法 => - 乘法 => * 除法 => / 次方 => ^ 取模 => % (讀音為mod 意為取模 講白話叫取餘數) ex: int i = 20, x = 3; double d = 20 % 3; // d = 2 ``` #### 邏輯運算 ``` && 及運算(AND運算) || 或運算(OR運算) ! 反向運算(NOT運算),範例如下 boolean flag = false; boolean result = !flag; 因為flag為false,所以!flag會是true ``` #### 關係運算 ``` > 大於 < 小於 == 等於 => 大於等於 <= 小於等於 != 不等於 ``` ## 邏輯 ### 判斷式 判斷式主要分為if、switch以及關係運算(又稱三元判斷) ### if的用法 ```flow st=>start: 開始 e=>end: 結束 con=>condition: 條件式(condition) init=>operation: 起始值(init) block=>operation: 執行內容(code block) inc=>operation: 更新值(increment) st->init->con con(yes)->block->inc->con con(no)->e ``` ```java= Boolean flag = false; if (flag == false) { //條件成立,執行大括號內的語法 System.out.println("flag values is false!"); } Boolean flag = true; if (flag == false) { //條件不成立,執行else大括號內的語法 System.out.println("flag values is false!"); } else { System.out.println("flag values is true!"); } String flag = "true"; if (flag == false) { //條件不成立,執繼續判斷else if是否成立 System.out.println("flag values is false!"); } else if (flag == true) { //條件不成立,執行else大括號內的語法 System.out.println("flag values is true!"); } else { System.out.println("flag type is not boolean!"); } ``` 以上三者輸出分別為 ``` 1、flag values is false! 2、flag values is true! 3、flag type is not boolean! ``` ### nested if ```java= import java.util.Scanner; public class Test { public static void main(String args[]) { Scanner scn = new Scanner(System.in); int num = scn.nextInt(); //假設輸入數字為59 String result; if (num > 100 | num < 0) { System.out.println("輸入分數錯誤!"); } else { if (num >= 90 && num <= 100) { //分數介於90到100之間 result = 'A'; } else { // 分數小於90 if (num >= 80) { //分數介於80到90之間 result = 'B'; } else { // 分數小於80 if (num >= 70) { //分數介於70到80之間 result = 'C'; } else { // 分數小於70 if (num >= 60) { //分數介於60到70之間 result = 'D'; } else { // 分數小於60 result = 'E'; } } } } System.out.println("result = " + result); } } } ``` 輸出 => `result = E` :::info 註 : 這邊import的Scanner是一種讀入功能的封裝 後面會做介紹 ::: ### switch switch是比對每一個case選項,當case選項的值符合傳入switch中的參數時,就會執行該case語法的判斷方式,可以有效避免大量使用else if的情況。 ```java= int iii = 123; switch(iii) { case 1: System.out.println("hi"); break; case 123: System.out.println("Hello, world"); break; case 2: System.out.println("123"); break; default: System.out.print("default"); } ``` 以上語法執行結果如下 ``` Hello, world ``` ### 關係運算(又稱三元判斷) 三元判斷一般在給定值時使用,它能一定程度上替代if和switch判斷式,用法如下 ```java= int iii = 123; String str; str = (iii > 100) ? "iii values > 100" : "iii values < 100"; System.out.println(str); ``` 輸出如下 ``` iii values > 100 ``` ## 迴圈 迴圈主要有for()、do...while()和while()迴圈,其用法如下 ### for loop ```java= int result = 0; for (int i = 0; i < 26; i++) { //宣告i初值為0,當i<26時執行迴圈,每次執行後i++ result += i; } System.out.printf("result的值為: %d", result); ``` 以上語法的輸出為 ``` result的值為: 325 ``` ### while ```java= int i = 0, index = 1; while(i < 20) { //當i < 20時執行迴圈 i++; //每次執行i就+1 index *= 2; } System.out.printf("index的值為%d", index); ``` 以上語法的輸出為 ``` index的值為: 1048576 ``` ### do...while ```java= int i = 0, index = 1; do { //先執行第一次do底下的語法,然後當i < 20時執行迴圈 i++; index *= 2; } while(i < 20); System.out.printf("index的值為%d", index); ``` 以上語法的輸出為 ``` index的值為: 1048576 ``` ### 巢狀迴圈 巢狀迴圈是在一個回圈內再執行一個迴圈,這種寫法在處理大型json資料或大型專案中常見,但處理不好容易成為無限迴圈,因此須謹慎撰寫 #### [延伸練習] 99乘法表 ```java= public class Test { public static void main(String args[]) { for (int i = 1; i < 10; i++) { for (int j = 1; j < 10; j++) { System.out.print(Integer.toString(i) + "x" + Integer.toString(j) + " = " + Integer.toString(i * j)); System.out.print(((i*j) < 10) ? " " : " "); } System.out.println(); } } } ``` ``` 1x1 = 1 1x2 = 2 1x3 = 3 1x4 = 4 1x5 = 5 1x6 = 6 1x7 = 7 1x8 = 8 1x9 = 9 2x1 = 2 2x2 = 4 2x3 = 6 2x4 = 8 2x5 = 10 2x6 = 12 2x7 = 14 2x8 = 16 2x9 = 18 3x1 = 3 3x2 = 6 3x3 = 9 3x4 = 12 3x5 = 15 3x6 = 18 3x7 = 21 3x8 = 24 3x9 = 27 4x1 = 4 4x2 = 8 4x3 = 12 4x4 = 16 4x5 = 20 4x6 = 24 4x7 = 28 4x8 = 32 4x9 = 36 5x1 = 5 5x2 = 10 5x3 = 15 5x4 = 20 5x5 = 25 5x6 = 30 5x7 = 35 5x8 = 40 5x9 = 45 6x1 = 6 6x2 = 12 6x3 = 18 6x4 = 24 6x5 = 30 6x6 = 36 6x7 = 42 6x8 = 48 6x9 = 54 7x1 = 7 7x2 = 14 7x3 = 21 7x4 = 28 7x5 = 35 7x6 = 42 7x7 = 49 7x8 = 56 7x9 = 63 8x1 = 8 8x2 = 16 8x3 = 24 8x4 = 32 8x5 = 40 8x6 = 48 8x7 = 56 8x8 = 64 8x9 = 72 9x1 = 9 9x2 = 18 9x3 = 27 9x4 = 36 9x5 = 45 9x6 = 54 9x7 = 63 9x8 = 72 9x9 = 81 ``` ## 陣列 ### 宣告一維陣列 java的陣列有區別型態,字串陣列只能存字串、整數陣列只能存整數,依此類推。 ```java= int integer_array[] = {1, 3, 99, -8888}; int[] integer_array[] = {8421, 7746, 65536, -65536}; String str_array[] = {"ho", "yu", "shit"}; String str_array[] = {"hi", "llo", "wol"}; ``` :::info 值得注意的是,上述兩種宣告方式都是可行的。 ::: ### 一維陣列應用 一維陣列常見應用方式的情況有以下幾種 讀取陣列值一般是使用for迴圈,常見寫法如下: - 讀取陣列值 ```java= public class Test { public static void main(String args[]) { int[] int_array = {2, 1, 4, 7, 4, 8, 3, 6, 4, 7}; // int_array.length => 取得int_array的陣列長度 for (int i = 0; i < int_array.length; i++) { // 印出int_array的第i個元素 System.out.println(int_array[i]); } } } ``` - 取得陣列內所有值的和 ```java= public class Test { public static void main(String args[]) { int[] int_array = {2, 1, 4, 7, 4, 8, 3, 6, 4, 7}; int sum = 0; // int_array.length => 取得int_array的陣列長度 for (int i = 0; i < int_array.length; i++) { // sum = sum + int_array[i]的值 sum += int_array[i]; } System.out.println(sum); // 輸出 46 } } ``` - 取得陣列內的最大值 / 最小值 ```java= public class Test { public static void main(String args[]) { int[] int_array = {1, 1, 4, 5, 1, 4, 2, 2, 8, 9, 2, 2, -6}; int max = int_array[0], min = int_array[0]; // int_array.length => 取得int_array的陣列長度 for (int i = 0; i < int_array.length; i++) { // 計算最大值 if (max < int_array[i]) { // 當int_array[i]的值大於max時,將max設為int_array[i] max = int_array[i]; } // 計算最小值 if (min > int_array[i]) { // 當int_array[i]的值小於min時,將min設為int_array[i] min = int_array[i]; } } System.out.println(max); // 輸出 9 System.out.println(min); // 輸出 -6 } } ``` - 反轉陣列 ```java= public class Test { public static void main(String args[]) { int[] int_array = {1, 1, 4, 5, 1, 4, 2, 2, 8, 9, 2, 2, -6}; int temp, len = int_array.length, replace = len / 2; // int_array.length => 取得int_array的陣列長度 // 宣告replace 是為了讓迴圈執行時不要重複計算陣列長度 / 2的值 // 讓迴圈的執行次數僅到陣列長度的一半 for (int i = 0; i < replace; i++) { temp = int_array[i]; // 取得陣列當前元素並暫存 /* 取得陣列倒數時的第i個元素 例: 陣列長度為8 當i = 0 時,陣列倒數第i個元素為陣列最後一個元素 當i = 1 時,陣列倒數第i個元素為陣列倒數第二個元素 ... 相當於將陣列對折取對應值 取得之後先將陣列第i個元素改寫成倒數第i個元素 */ int_array[i] = int_array[len - i - 1]; // 將剛剛暫存起來的陣列第i個元素設定到陣列倒數第i的位置 int_array[len - i - 1] = temp; } } } ``` ### 宣告二維陣列 java的一維陣列有區別型態,二維陣列同樣如此。 ```java= int integer_array[][] = { {-21, 3, 87, -8888}, {199, 13, 88, 8889}, {45, 9, 89, -8987} }; ``` ### 二維陣列應用 - 遍歷陣列元素(讀取所有元素) - 橫向遍歷 ```java= public class Test { public static void main(String args[]) { int int_array[][] = { {-21, 3, 87, -8888}, {199, 13, 88, 8889}, {45, 9, 89, -8987} }; // int_array.length => 取得int_array的陣列長度 for (int i = 0; i < int_array.length; i++) { // int_array[i].length => 取得int_array中當前子元件的陣列長度 for (int j = 0; j < int_array[i].length; j++) { System.out.println(int_array[i][j]); } } } } ``` - 縱向遍歷 使用前提:陣列內的所有子陣列長度必須一致 ```java= public class Test { public static void main(String args[]) { int int_array[][] = { {-21, 3, 87, -8888}, {199, 13, 88, 8889}, {45, 9, 89, -8987} }; // int_array.length => 取得int_array的陣列長度 for (int i = 0; i < 4; i++) { for (int j = 0; j < int_array.length; j++) { System.out.println(int_array[j][i]); } } } } ``` - 取二維陣列中滿足除某數等於0的數 ```java= public class Test { public static void main(String[] args) { int int_array[][] = { {-21, 3, 87, -8888}, {199, 13, 88, 8889}, {45, 9, 89, -8987} }; int condition = 3; for (int i = 0; i < int_array.length; i++) { for (int j = 0; j < int_array[i].length; j++) { if (int_array[i][j] % condition == 0) { System.out.println(int_array[i][j]); } } } } } ``` - 取二維陣列中值的總和 ```java= public class Test { public static void main(String[] args) { int int_array[][] = { {-21, 3, 87, -8888}, {199, 13, 88, 8889}, {45, 9, 89, -8987} }; int sum = 0; for (int i = 0; i < int_array.length; i++) { for (int j = 0; j < int_array[i].length; j++) { sum += int_array[i][j]; } } } } ``` - 取二維陣列中的最大 / 最小值 ```java= public class Test { public static void main(String[] args) { int int_array[][] = { {-21, 3, 87, -8888}, {199, 13, 88, 8889}, {45, 9, 89, -8987} }; int max = int_array[0][0], min = int_array[0][0]; for (int i = 0; i < int_array.length; i++) { for (int j = 0; j < int_array[i].length; j++) { // 取最大值 if (max < int_array[i][j]) { max = int_array[i][j]; } //取最小值 if (min > int_array[i][j]) { min = int_array[i][j]; } } } } } ``` - 二維陣列反轉 ```java= public class Test { public static void main(String[] args) { int int_array[][] = { {-21, 3, 87, -8888}, {199, 13, 88, 8889}, {45, 9, 89, -8987} }; int count = int_array.length; int len = count / 2; int[] temp = {}; // int_array.length => 取得int_array的陣列長度 for (int i = 0; i < len; i++) { // int_array[i].length => 取得int_array中當前子元件的陣列長度 temp = int_array[i]; // 將int_array當前的子元件暫存 int_array[i] = int_array[count - (i + 1)]; // 將int_array當前的子元件變成陣列對折時對應位置之子元件 int_array[count - (i + 1)] = temp; // 將int_array陣列對折時對應位置之子元件變成當前的子元件 } } } ``` ## 物件導向 ### 何謂物件 物件(Object),是一個類別(Class)的實際運用。 講起來很抽象,舉個例子 : 以"人"這個物件作為例子 "人"這個概念本身是一個類別,類別定義了一件事物的抽象特點。 "人"這個類別包含了他本身會觸發的事件(方法),以及其他的屬性(變數) 例如: "人"是一個類別,而這個類別內包含了許多屬性,如"穿著"或"種族"等等屬性; 而改變這些屬性需要透過方法(Method),假設要改變"穿著"這個屬性,需要透過換衣服來達成,"換衣服"這個動作就是方法的一種。 ### 套件 套件(package),通常用於定義程式範圍 定義接近於PHP中的namespace 那套件有甚麼用呢? 可以隔離不同環境下相同物件名稱導致的編譯錯誤 可以用以劃分功能與架構 舉以下例子: ```java= /* 分析工具 */ package analyze; class Tool { } ``` ```java= /* 資料庫操作工具 */ package database; class Tool { } ``` 可以看到我在兩個package中分別實作了相同名稱的class 如果要分別調用他們,可以像這樣: ```java= package domainservice; public class Main { public static void Main(String args[]) { // 初始化資料庫操作工具類別 database.Tool dbTool = new database.Tool(); // code... // 初始化分析工具類別 analyze.Tool analyzeTool = new analyze.Tool(); // code... } } ``` 由於套件在JAVA中的設計是與檔案系統對應的 因此檔案結構應該要像這樣: ``` / root directory (根目錄) ├── package directory (package目錄) │ ├── domainservice │ │ └── Main.java (java程式) │ ├── database │ │ └── Tool.java (java程式) │ └── analyze │ └── Tool.java (java程式) ``` ### 物件 物件在Java中代表的是類別(Class)、方法(Method,或稱Function)和變數(Variable),層級關係如下: :::info 類別 > 方法 > 變數 ::: 在物件的上層則是package,層級關係如: :::success 套件 > 類別 > 方法 > 變數 ::: 類別又分外部類別與內部類別,其特徵如下: :::spoiler Code ```java= // file name = Test.java // 外部類別 public class Test { public static void main(String args[]) { // code... } } // 內部類別 class AAAA { public AAAA(String shark, int args) { // code... } } ``` ::: 可以看到,外部類別的結構就是很常見的java class,裡面一定要定義main function,且class名稱要和檔案名稱一樣;而內部類別則可以任意定義,入口function的名稱則須與class名稱一致。 ### 靜態物件 在Java中,方法和變數有分為靜態與物件(非靜態)方法/物件,以下舉個關於靜態方法的簡單例子: 例如一個公開類別名叫"我",有個方法叫"花光我的積蓄當月光仙子" 如果他是物件(非靜態)方法,那麼可以確定只有"我"可以執行"花光我的積蓄當月光仙子" 如果他是靜態方法那就好玩了,就算是路人類別也能執行"我.花光我的積蓄當月光仙子()"方法 然後"我"的薪水就被花光了,而且執行的類別還不是"我" - 摘錄自[Mr.Wei 的程式筆記](http://weisnote.blogspot.com/2012/08/static.html) 靜態與物件方法的表示方式如下: ```java= public class Test { public static void main(String args[]) { // 物件函數呼叫 Test object = new Test(); object.nonStaticfun(); // 靜態函數呼叫 isStaticfun(); } // 靜態函數 static void isStaticfun() { // code } // 物件函數 void nonStaticfun() { // code } } ``` ### 存取修飾子 存取修飾子決定了屬性、方法或物件的可存取性 但屬性、方法以及物件各自可以應用的修飾子不同,不同語言中也有不同限制 #### 修飾子介紹 修飾子有以下四個種類: - `public` (公開) - `protected` (保護) - `private` (私有) - ` `(預設) 你沒看錯,有一個修飾子是空的 這是預設的修飾子,存取權限如下: **公開 / public** 就如同字面意思一樣,任何地方都可以存取 **保護 / protected** - 同package可以存取 - 不同package中的子類別(sub class)可以存取 **預設 / No Modifier** - 同package中可以存取 **私有 / private** - 同class中可以存取 按照可存取範圍由大到小排序分別是: ```java= public > protected > > private ``` #### 類別 在JAVA中,類別只能應用`public`與` `修飾子 單一`.java`檔案中只能有一個`public class` 並且使用`public`修飾子的**class名稱必須與檔名完全相同** ```java= /* Human.java */ public class Human {} class Tool {} ``` 以上案例中`public class`是`Human` 其他的類別就不需要攜帶修飾子 #### 方法與屬性 方法與屬性就可以應用全部的修飾子,根據權限不同來決定存取範圍 以下建立一個公司職員的物件,用以說明修飾子的作用: ```java= package company; // 職員 class Staff { // 姓名 public String Name; // 所屬部門 String Branch; // 負責項目 protected String ResponsibleProject; // 電腦密碼 private String PCPassword; } ``` **姓名** 可以被任何人知道,因此是`public` **所屬部門** 相同公司(package)的成員可以知道所屬的部門 **負責項目** 只有相關的團隊成員和上司可以知道負責的項目 **電腦密碼** 只有自己可以知道電腦密碼是多少 ### 封裝 **請搭配上方的修飾子食用** 物件導向最基本的原則,把真實世界的某個事物包成物件,裡面的資訊不對外公開,只公開某些特定方法讓別人使用,內部的實做及資料都隱藏起來,不讓人直接使用,也不需要讓別人直接使用。 也就是所謂的 資訊隱藏(Information Hiding) 假設我想在程式中建立一系列物件,其中包含了"人類" :::spoiler 範例 code ```java= class Human { // 姓名 private String name; // 國籍 private String country; // 性別 private String sex; // 身分證字號 private String idCradNumber; // 銀行卡密碼 private String bankPassword; // 吃東西 public void Eat() { // code... } // 睡覺 public void Sleep() { // code... } // 取得姓名 public String GetName() { return this.name; } // 取得國籍 public String GetCountry() { return this.country; } // 取得性別 public String GetSex() { return this.sex; } // 設定銀行卡密碼 public void SetBankPwd(String password) { this.bankPassword = password; } } ``` ::: 這裡構建了"人類"物件後,我們可以將吃飯、睡覺等相關的方法都構建到"人類"物件中 而人類相關屬性不能直接被存取,透過公開出來的**Getter**才可以被存取 相對的,人類相關屬性也不能直接被覆寫,要透過公開出來的**Setter**才可以覆寫 #### Getter 存取物件屬性的方法,可以透過修飾子決定什麼屬性可以被什麼成員存取 並且可以在Getter中實作其他邏輯來判斷能不能存取屬性 #### Setter 覆寫物件屬性的方法,同樣可以透過修飾子決定什麼屬性可以被什麼成員存取 並且同樣可以在Setter中實作其他邏輯來判斷能不能覆寫屬性 ### 繼承 在物件導向的語言中,類別能夠透過繼承,藉此引繼父類別的屬性 以下舉幾個簡單的例子 : "人"是一個類別,裡面包含了基本的屬性跟方法: ```java= class Human { // 姓名 public String Name; // 國籍 public String Country; // 性別 public String Sex; // 身分證字號 public String IDCradNumber; // 吃東西 public void Eat() { // code... } // 睡覺 public void Sleep() { // code... } } ``` 如果要建立"女人"物件,就需要在"人"的基礎上建立 ```java= class Woman extends Human { // 女人的體重是秘密,要使用private private float Weight; // 化妝 public void MakeUp() { // code... } } ``` 按照這種方式建立的"女人"物件,就同時繼承了"人"的屬性和方法 這時候如果你想讓女人執行睡覺方法,就不需要重複定義`Sleep()` 可以直接調用從父類別`Human`繼承來的`Sleep()`方法 > 不要物化女性 ## 補充課程 ### 不用BigInteger的極大數值加法運算 不用BigInteger來進行大數運算 :::spoiler 程式碼 ```java= import java.util.Scanner; public class Test { public static void main(String args[]) { Scanner scn = new Scanner(System.in); String a = scn.nextLine(); String b = scn.nextLine(); Test myclass = new Test(); String result = myclass.doAdd(a, b); System.out.println(result); } private String doAdd(String a, String b) { String str = ""; //取得 a , b 數字字串長度 int lenA = a.length(); int lenB = b.length(); //比較 a , b ,取得最大長度 & 最小長度 int maxLen = Math.max(lenA, lenB); int minLen = Math.min(lenA, lenB); StringBuilder strTmp = new StringBuilder(); for (int i = maxLen - minLen; i > 0; i--) { strTmp.append("0"); } //把長度调整到相同 if (maxLen == lenA) { b = strTmp + b; } else { a = strTmp + a; } //進位旗標 int JW = 0; for (int i = maxLen - 1; i >= 0; i--) { int tempA = Integer.parseInt(String.valueOf(a.charAt(i))); int tempB = Integer.parseInt(String.valueOf(b.charAt(i))); int temp; if (tempA + tempB + JW >= 10 && i != 0) { temp = tempA + tempB + JW - 10; JW = 1; } else { temp = tempA + tempB + JW; JW = 0; } str = temp + str; } return str; } } 瑪利歐