# JAVA 筆記 `Note` `2025.02.28` - Start: [time=Wed, May 28, 2025 1:50 PM] - Last Update: [time=Mon, Nov 17, 2025 8:52 AM] ## 資料型別與變數宣告 Java 是強型別語言,變數必須先宣告型別才能使用。 ### 原始型別(Primitive Types) - `int`、`long`、`float`、`double` → 數值 - `char` → 單一字元 - `boolean` → `true` / `false` ```java int age = 25; double pi = 3.14159; char grade = 'A'; boolean isJavaFun = true; ``` ### 參考型別(Reference Types) - `String`、`Array`、`ArrayList`、`HashMap`、自訂 `class` - 儲存的是「物件的記憶體位址」 ```java String name = "Charlie"; int[] numbers = {1, 2, 3}; ``` ### 資料型別與變數宣告 在 Java 中,變數必須先宣告型別,才能儲存資料。主要分為兩大類: #### 原始資料型別(Primitive Data Types) Java 內建 8 種基本型別,直接儲存值(copy by value)。 | 型別 | 位元組 | 範例值 | 範圍 | |-----------|--------|--------|------| | `byte` | 1 | `127` | -128 ~ 127 | | `short` | 2 | `32000`| -32,768 ~ 32,767 | | `int` | 4 | `1000` | -2,147,483,648 ~ 2,147,483,647 | | `long` | 8 | `100000L` | -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 | | `float` | 4 | `3.14f` | 約 ±3.4E38 | | `double` | 8 | `3.14159` | 約 ±1.7E308 | | `char` | 2 | `'A'` | Unicode (0 ~ 65535) | | `boolean` | 1 | `true` | `true` / `false` | **注意**: - `long` 常數要加 `L`,例如 `long num = 123456789L;` - `float` 常數要加 `f`,例如 `float pi = 3.14f;` - `char` 使用單引號 `'A'`,字串則用雙引號 `"Hello"` #### 參考資料型別(Reference Data Types) 這類型別不直接存值,而是存「記憶體位址的參考」(copy by reference)。 - 常見的有:`String`, `Array`, `ArrayList`, `HashMap`, `Object` - 使用者自訂的 `class` 也屬於參考型別 ```java // Primitive 範例 int a = 10; int b = a; // copy by value b = 20; System.out.println(a); // 仍然是 10 // Reference 範例 StringBuilder x = new StringBuilder("Hi"); StringBuilder y = x; // copy by reference y.append("!"); System.out.println(x); // 輸出 "Hi!" ``` #### 常數(final) 如果變數值不允許被修改,可以用 `final` 宣告: ```java final double PI = 3.1415926; // PI = 3.15; // X 編譯錯誤,因為 final 不能再被修改 ``` #### 小結 - **Primitive**:直接存值,複製時互不影響 - **Reference**:存位址,複製時會指向同一物件 - **final**:宣告常數,值不可變 ## 控制流程 控制程式執行的邏輯分支與迴圈。 ### 語法基礎 - 資料型別與變數宣告 - 控制流程:`if`, `switch`, `for`, `while` - 陣列與集合:`Array`, `ArrayList`, `HashMap` - 方法與參數傳遞(值 vs 參考) ```java public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, Java!"); } } ``` ### 條件判斷 #### If ```java int score = 85; if (score >= 90) { System.out.println("優秀"); } else if (score >= 60) { System.out.println("及格"); } else { System.out.println("不及格"); } ``` #### Switch ```java int day = 3; switch (day) { case 1: System.out.println("星期一"); break; case 2: System.out.println("星期二"); break; case 3: System.out.println("星期三"); break; default: System.out.println("其他"); } ``` ### 迴圈 ```java // for for (int i = 0; i < 5; i++) { System.out.println("i = " + i); } // while int j = 0; while (j < 5) { System.out.println("j = " + j); j++; } ``` ## 陣列與集合 ### 陣列(Array) 固定長度,元素型別一致。 ```java int[] arr = {10, 20, 30}; System.out.println(arr[1]); // 20 ``` ### ArrayList 可動態增減元素。 ```java import java.util.ArrayList; ArrayList<String> list = new ArrayList<>(); list.add("Java"); list.add("Python"); System.out.println(list.get(0)); // Java ``` ### HashMap 鍵值對(Key-Value)結構。 ```java import java.util.HashMap; HashMap<String, Integer> map = new HashMap<>(); map.put("apple", 3); map.put("banana", 5); System.out.println(map.get("apple")); // 3 ``` #### 方法與參數傳遞 Java 方法可重複使用程式碼,並支援「值傳遞」與「參考傳遞」。 #### 值傳遞(Primitive) ```java public static void changeValue(int x) { x = 100; } public static void main(String[] args) { int a = 10; changeValue(a); System.out.println(a); // 仍然是 10 } ``` #### 參考傳遞(Reference) ```java public static void changeArray(int[] arr) { arr[0] = 99; } public static void main(String[] args) { int[] nums = {1, 2, 3}; changeArray(nums); System.out.println(nums[0]); // 99 } ``` #### Hello World 範例 ```java public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, Java!"); } } ``` 說明: - `public class HelloWorld` → 定義一個類別 - `public static void main(String[] args)` → 主程式進入點 - `System.out.println()` → 輸出文字到終端機 ## 物件導向設計(OOP) ### 比較表 | 概念名稱 (中文) | 英文名稱 (English) | 核心定義與關係 | 範例程式碼 (Code Snippet) | | :--- | :--- | :--- | :--- | | **類別** | **Class** | **藍圖 (Blueprint) 或模板。** 它定義了物件的屬性與行為。 | `public class Car { }` | | **物件** | **Object** | **實體 (Entity) 或實例 (Instance)。** 它是根據類別所建立出來的具體實體。 | `Car myCar = new Car();` | | **實例** | **Instance** | 物件的同義詞,一個物件就是一個類別的實例。 | `myCar` | | **實例化** | **Instantiation** | 建立物件的過程,使用 `new` 關鍵字。 | `new Car()` | | **屬性** | **Attribute / Field** | 類別中的資料成員,描述物件的**狀態**。 | `public String color;` | | **方法** | **Method** | 類別中的函數成員,描述物件的**行為**。 | `public void startEngine() { ... }` | | **建構子** | **Constructor** | 在物件被實例化時自動呼叫,用於**初始化屬性**。 | `public Car(String c) { this.color = c; }` | | **`this` 關鍵字** | **`this` keyword** | 代表**當前物件實例**本身。 | `this.color = color;` | | **封裝** | **Encapsulation** | **物件導向三大特性之一。** 將資料 (屬性) 和方法 (行為) 綑綁在一起,並使用 `private` 隱藏內部細節,僅透過 `public` 方法 (Getter/Setter) 供外部安全存取。 | `private String name;` <br> `public String getName() { return name; }` | | **繼承** | **Inheritance** | **物件導向三大特性之一。** 允許子類別繼承父類別的屬性和方法,實現程式碼重用。 | `public class SportsCar extends Car { }` | | **多型** | **Polymorphism** | **物件導向三大特性之一。** 「一個介面,多種行為」。指一個物件可以呈現多種型態,並根據實際物件類型執行對應的方法。主要體現為:<br>1. **覆寫 (Overriding):** 子類別重新實作父類別的方法。<br>2. **多載 (Overloading):** 同一名稱的方法,但參數列表不同。 | `Car c = new SportsCar();` <br> `c.startEngine();` (執行 SportsCar 的方法) | | **靜態成員** | **Static Member** | 屬於**類別本身**,不屬於任何特定物件實例,所有實例共享。 | `public static int wheelCount = 4;` | | **抽象類別** | **Abstract Class** | 不能被直接實例化,用作其他類別繼承的基礎模板。 | `public abstract class Vehicle { ... }` | | **介面** | **Interface** | 一種純粹的**規格**或**契約**,只包含方法簽章 (沒有實作細節)。 | `public interface Drivable { void drive(); }` | - **補充說明**:封裝 (Encapsulation) 封裝的核心目的是保護資料的完整性和隱密性,並提高程式的穩定性。 **實踐方式**: 通常將類別的資料成員 (Fields) 宣告為 private,讓外部無法直接存取和修改。 **介面提供**: 接著提供 public 的 Getter (讀取資料) 和 Setter (寫入資料) 方法,作為外部與內部資料溝通的唯一管道。這樣可以在 Setter 方法中加入邏輯檢查(例如:年齡不能為負數),以控制資料的有效性。 - **補充說明**:**多型** (Polymorphism) 多型的核心概念是讓程式碼更具彈性和擴展性。 Java 採用 **物件導向程式設計(Object-Oriented Programming, OOP)**,核心概念包含: - 類別與物件 - 封裝、繼承、多型 - `interface` vs `abstract class` ```java interface Sorter { void sort(int[] arr); } class BubbleSorter implements Sorter { public void sort(int[] arr) { // 泡泡排序邏輯 } } ``` #### 類別與物件(Class & Object) - **類別(Class)**:定義資料結構與行為的「藍圖」 - **物件(Object)**:依照類別建立的實體 ```java class Student { String name; int age; void study() { System.out.println(name + " 正在學習 Java"); } } public class Main { public static void main(String[] args) { Student s1 = new Student(); // 建立物件 s1.name = "Hsieh"; s1.age = 25; s1.study(); // 輸出:Hsieh 正在學習 Java } } ``` ### Encapsulation ```java= public class Person { // 私有欄位:外部無法直接存取 private String name; private int age; // 建構子 public Person(String name, int age) { this.name = name; setAge(age); // 使用 setter 方法以便驗證 } // 公開的 getter 方法 public String getName() { return name; } public int getAge() { return age; } // 公開的 setter 方法,加入驗證邏輯 public void setName(String name) { this.name = name; } public void setAge(int age) { if (age >= 0) { this.age = age; } else { System.out.println("年齡不能是負數!"); } } } ``` ```java= public class Main { public static void main(String[] args) { Person p = new Person("Alice", 25); System.out.println(p.getName()); // 輸出:Alice System.out.println(p.getAge()); // 輸出:25 p.setAge(-5); // 嘗試設定非法年齡,會觸發驗證 System.out.println(p.getAge()); // 輸出仍為:25 } } ``` #### 封裝(Encapsulation) - 將資料與方法「包裝」在類別中,並透過 **存取修飾子** 控制可見性 - 常見修飾子:`public`, `private`, `protected` - 好處:保護資料、避免外部隨意修改 ```java class Account { private int balance = 1000; public int getBalance() { return balance; } public void deposit(int amount) { if (amount > 0) balance += amount; } } ``` #### 多型(Polymorphism) - 相同的方法呼叫,依物件型別不同而有不同表現 - 透過 **方法覆寫(Override)** 或 **介面實作** 達成 ```java class Animal { void speak() { System.out.println("動物發出聲音"); } } class Dog extends Animal { @Override void speak() { System.out.println("汪汪!"); } } class Cat extends Animal { @Override void speak() { System.out.println("喵喵!"); } } public class Main { public static void main(String[] args) { Animal a1 = new Dog(); Animal a2 = new Cat(); a1.speak(); // 汪汪! a2.speak(); // 喵喵! } } ``` ### Inheritance ```java= // 父類別 class Animal { String name; public void eat() { System.out.println(name + " is eating."); } } // 子類別 class Dog extends Animal { public void bark() { System.out.println(name + " is barking."); } } ``` ```java= public class Main { public static void main(String[] args) { Dog myDog = new Dog(); myDog.name = "Buddy"; myDog.eat(); // 繼承自 Animal myDog.bark(); // Dog 自己的方法 } } ``` --- ```java= interface A { void methodA(); } interface B extends A { void methodB(); } class MyClass implements B { public void methodA() { System.out.println("methodA 實作"); } public void methodB() { System.out.println("methodB 實作"); } } ``` ```java= public class Main { public static void main(String[] args) { MyClass obj = new MyClass(); obj.methodA(); // 輸出:methodA 實作 obj.methodB(); // 輸出:methodB 實作 } } ``` ```java= interface X { void x(); } interface Y { void y(); } interface Z extends X, Y { void z(); } ``` ### Abstract Class | 特性 | 抽象類別 (`abstract class`) | 介面 (`interface`) | |------------------|-----------------------------|-----------------------------| | 是否可包含實作 | **V** 可以 | **V** Java 8+ 可有 default 方法 | | 是否可有建構子 | **V** 可以 | **X** 不可 | | 多重繼承支援 | **X** 不支援類別多重繼承 | **V** 可實作多個介面 | | 成員修飾詞 | 可用 `private`, `protected` | 預設為 `public` | ```java= // 抽象類別 abstract class Animal { String name; // 抽象方法:沒有方法體,子類別必須實作 abstract void makeSound(); // 一般方法:子類別可以直接使用或覆寫 public void sleep() { System.out.println(name + " is sleeping."); } } ``` ```java= class Dog extends Animal { public void makeSound() { System.out.println(name + " says: Woof!"); } } ``` ```java= public class Main { public static void main(String[] args) { Dog myDog = new Dog(); myDog.name = "Buddy"; myDog.makeSound(); // 輸出:Buddy says: Woof! myDog.sleep(); // 輸出:Buddy is sleeping. } } ``` #### `interface` vs `abstract class` - **interface(介面)**:定義「行為規範」,不能有實作(Java 8+ 可有 `default` 方法) - **abstract class(抽象類別)**:可包含「部分實作」與「抽象方法」 | 特性 | interface | abstract class | |------|-----------|----------------| | 多重繼承 | **V** 可實作多個 | **X** 只能繼承一個 | | 成員變數 | 預設 `public static final` | 可有一般屬性 | | 方法 | 抽象方法(Java 8+ 可有 `default`) | 可有抽象與具體方法 | | 使用場景 | 定義規範(行為契約) | 提供部分共用邏輯 | ```java interface Sorter { void sort(int[] arr); } abstract class AbstractSorter { abstract void sort(int[] arr); void printArray(int[] arr) { for (int n : arr) System.out.print(n + " "); System.out.println(); } } class BubbleSorter extends AbstractSorter implements Sorter { @Override public void sort(int[] arr) { // 泡泡排序邏輯 } } ``` #### 小結 - **類別與物件**:藍圖與實體 - **封裝**:保護資料,提供介面 - **繼承**:重用程式碼,建立階層 - **多型**:相同介面,不同行為 - **interface vs abstract class**:規範 vs 部分實作 ## 資料結構與演算法 ### 演算法與資料結構 - 排序法:泡泡排序、選擇排序、快速排序 - 搜尋法:線性搜尋、二分搜尋 - 樹結構:Binary Tree 範例與遍歷(Pre/In/Post) #### 泡泡排序法 ```java= public class BubbleSort { public static void main(String[] args) { int[] arr = {3, 4, 0, 1, 2, 5, 6, 9, 7, 8}; int arr_n = arr.length; System.out.println("arr 陣列的長度 arr_n=" + arr_n); System.out.println("arr--- (Original)"); printArray(arr); int i = arr_n; while (i > 0) { int j = 1; while (j < i) { if (arr[j] < arr[j - 1]) { int w = arr[j]; arr[j] = arr[j - 1]; arr[j - 1] = w; System.out.println("\nw=" + w + " \t---"); printArray(arr); } j++; } i--; } System.out.println("\n"); System.out.println("arr--- (Sorted)"); printArray(arr); } // 輔助函式:用來列印陣列 public static void printArray(int[] arr) { for (int k = 0; k < arr.length; k++) { System.out.print(arr[k] + "\t"); } System.out.println(); // 換行 } } ``` - [time=Tue, Nov 11, 2025 9:04 PM] ### 泡泡排序法 物件導向 ```java= import java.util.Arrays; // 定義一個排序器介面 interface Sorter { void sort(int[] arr); } // 實作泡泡排序的類別 class BubbleSorter implements Sorter { @Override public void sort(int[] arr) { // 為了避免 NullPointerException,先進行 null 值檢查 if (arr == null || arr.length <= 1) { return; } int n = arr.length; boolean swapped; for (int i = 0; i < n - 1; i++) { swapped = false; for (int j = 0; j < n - i - 1; j++) { if (arr[j] > arr[j + 1]) { // 交換元素 int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; swapped = true; } } if (!swapped) { break; } } } } public class OOPSortingExample { public static void main(String[] args) { int[] arr = {5, 1, 4, 2, 8}; System.out.println("原始陣列: " + Arrays.toString(arr)); // 創建一個 BubbleSorter 物件 Sorter mySorter = new BubbleSorter(); // 呼叫物件的方法來進行排序 mySorter.sort(arr); System.out.println("排序後的陣列: " + Arrays.toString(arr)); } } ``` - [time=Mon, Nov 17, 2025 8:52 AM] ### Binary Tree ```java= public class BinaryTree { // 定義二元樹節點結構 static class Node { int data; Node left; Node right; Node(int data) { this.data = data; this.left = null; this.right = null; } } // 建立新節點 static Node createNode(int data) { return new Node(data); } // 修改節點資料 static void modifyNode(Node node, int newData) { if (node != null) { node.data = newData; } } // 前序遍歷:根 → 左 → 右 static void preOrderTraversal(Node root) { if (root != null) { System.out.print(root.data + " "); preOrderTraversal(root.left); preOrderTraversal(root.right); } } // 中序遍歷:左 → 根 → 右 static void inOrderTraversal(Node root) { if (root != null) { inOrderTraversal(root.left); System.out.print(root.data + " "); inOrderTraversal(root.right); } } // 後序遍歷:左 → 右 → 根 static void postOrderTraversal(Node root) { if (root != null) { postOrderTraversal(root.left); postOrderTraversal(root.right); System.out.print(root.data + " "); } } public static void main(String[] args) { // 建立節點並構建樹結構 Node root = createNode(0); root.left = createNode(1); root.right = createNode(2); root.left.left = createNode(3); root.left.right = createNode(4); root.right.left = createNode(5); root.right.right = createNode(6); root.left.left.left = createNode(7); root.left.left.right = createNode(8); root.left.right.left = createNode(9); System.out.print("Pre-order Traversal: "); preOrderTraversal(root); System.out.println(); System.out.print("In-order Traversal: "); inOrderTraversal(root); System.out.println(); System.out.print("Post-order Traversal: "); postOrderTraversal(root); System.out.println(); } } ``` ``` Pre-order Traversal: 0 1 3 7 8 4 9 2 5 6 In-order Traversal: 7 3 8 1 9 4 0 5 2 6 Post-order Traversal: 7 8 3 9 4 1 5 6 2 0 ``` - [time=Tue, Sep 16, 2025 3:37 PM] ### 二分搜尋法 ```java= public class SortAndSearch { // 泡泡排序法 public static void bubbleSort(int[] arr) { int i = arr.length; while (i > 0) { int j = 1; while (j < i) { if (arr[j] < arr[j - 1]) { // 交換 arr[j] 和 arr[j-1] int w = arr[j]; arr[j] = arr[j - 1]; arr[j - 1] = w; } j++; } i--; } } // 二分搜尋法 public static int binarySearch(int[] arr, int target) { int left = 0; int right = arr.length - 1; System.out.println("搜尋對象: " + target); while (left <= right) { int moderate = (left + right) / 2; System.out.println("取中間數: " + moderate); if (arr[moderate] == target) { return moderate; // 找到目標 } else if (arr[moderate] < target) { left = moderate + 1; System.out.println("往右邊找!"); } else { right = moderate - 1; System.out.println("往左邊找!"); } } return -1; // 沒找到 } public static void main(String[] args) { // 未排序的陣列 int[] arr = {5, 2, 9, 1, 7, 6, 3, 8, 0, 4}; int target = 2; System.out.print("原始陣列:\t"); for (int value : arr) { System.out.print(value + " "); } System.out.println(); // 排序陣列 bubbleSort(arr); System.out.print("排序後的陣列:\t"); for (int value : arr) { System.out.print(value + " "); } System.out.println(); // 查找目標值 int result = binarySearch(arr, target); if (result != -1) { System.out.printf("找到數值 %d 在索引位置 %d。\n", target, result); } else { System.out.printf("找不到數值 %d。\n", target); } } } ``` ``` Output: 原始陣列: 5 2 9 1 7 6 3 8 0 4 排序後的陣列: 0 1 2 3 4 5 6 7 8 9 搜尋對象: 2 取中間數: 4 往左邊找! 取中間數: 1 往右邊找! 取中間數: 2 找到數值 2 在索引位置 2。 ``` - [time=Tue, Sep 16, 2025 3:51 PM] ### 測試與除錯 - 單元測試:JUnit 基礎 - 例外處理:`try-catch-finally` - 日誌紀錄:`System.out` vs `Logger` 在 Java 中,**命令列輸入(Command Line Input)** 主要有三種常見方式,依需求不同可以選擇: #### 使用 `args[]` 接收命令列參數 這是最基本的方式,直接透過 `main(String[] args)` 取得執行程式時輸入的參數。 ```java public class Echo { public static void main(String[] args) { for (String s : args) { System.out.println("輸入參數: " + s); } } } ``` 執行方式(假設檔名為 `Echo.java`): ```bash javac Echo.java java Echo Hello 123 World ``` 輸出: ``` 輸入參數: Hello 輸入參數: 123 輸入參數: World ``` - 適合用於「一次性」傳入參數,例如檔案名稱、設定值。 #### 使用 `Scanner` 讀取使用者輸入 `Scanner` 是最常用的互動式輸入工具,能讀取字串、整數、浮點數等。 ```java import java.util.Scanner; public class InputExample { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.print("請輸入名字: "); String name = sc.nextLine(); System.out.print("請輸入年齡: "); int age = sc.nextInt(); System.out.println("Hello " + name + ", 你今年 " + age + " 歲。"); } } ``` 執行後會等待使用者輸入: ``` 請輸入名字: Hsieh 請輸入年齡: 25 Hello Hsieh, 你今年 25 歲。 ``` - 適合互動式程式,例如問答、表單輸入。 #### 使用 `BufferedReader`(較舊但效能佳) 比 `Scanner` 更早出現,適合需要快速讀取大量文字的情境。 ```java import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; public class BufferedInput { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.print("請輸入一句話: "); String line = br.readLine(); System.out.println("你輸入的是: " + line); } } ``` - 適合處理大量文字輸入(例如讀檔、批次輸入)。 #### 使用 `Console`(進階) `System.console()` 可讀取輸入,並支援「隱藏輸入」(例如密碼)。 - 注意:在 IDE(如 IntelliJ、Eclipse)中通常無法使用,需在終端機執行。 ```java public class ConsoleInput { public static void main(String[] args) { java.io.Console console = System.console(); if (console != null) { String user = console.readLine("請輸入使用者名稱: "); char[] pwd = console.readPassword("請輸入密碼: "); System.out.println("使用者: " + user); } else { System.out.println("Console 不可用,請在終端機執行。"); } } } ``` #### 小結 - **`args[]`** → 適合一次性參數(如檔案路徑)。 - **`Scanner`** → 最常用,適合互動式輸入。 - **`BufferedReader`** → 效能佳,適合大量文字。 - **`Console`** → 支援隱藏輸入,適合密碼輸入。 ### 專案結構與模組化 - `package` 使用與命名慣例 - 多檔案專案架構 - Maven/Gradle 基礎 ### 延伸應用(模組) - Java GUI:Swing / JavaFX - Java Web:Servlet / Spring Boot - Android 開發(Java 基礎) #### Acknowledge * [C筆記](https://hackmd.io/@EIT-/c_) * [排序與二元樹_Java](https://hackmd.io/@EIT-/algo_java) * [Java SE8 OCAJP專業認證指南](https://www.books.com.tw/products/E050057008?sloc=main) * [Java SE8 OCPJP進階認證指南](https://www.books.com.tw/products/E050057009?loc=P_br_r0vq68ygz_D_2aabd0_C_2) * [圖說演算法:使用Java](https://www.books.com.tw/products/0010845577?srsltid=AfmBOorSBSqLayCMDhKlKUbhG0chwU_glufk4z3ZesciogVpXzFTCEqK)