從零開始的JAVA-伊始之地 === ###### tags: `程式設計` `JAVA` :::success 🤖 本篇由 [**chatGPT**](https://platform.openai.com/) 及 [**Mai.Coding**](https://hackmd.io/@0x0607) 共同彙整 目前不考慮出第二篇,統整資料好累 ::: # **認識JAVA** :::info 💡 介紹一些關於JAVA的故事及特色 ::: ## Java歷史 - **Java** 是由 **James Gosling**、**Mike Sheridan** 和 **Patrick Naughton** 於 **1991 年**開發的程式語言,當時他們在 **Sun Microsystems** 工作。 - 在開發過程中,他們將 **Java** 設計為一種**跨平台**的語言,可以運行在不同的操作系統和硬體上。 - **第一版** **Java** 公開日期為 **1995 年 5 月 23 日**,當時 Java 還被稱為 **Oak**。 - **Java** 後來被 **Sun Microsystems** 正式命名為 Java, 並在 **1996年** 推出了 **Java 1.0** 版本。 - **Java** 每年都持續更新,並且由 **Oracle** 公司負責維護和開發。 - **Java 1.0** 和 **1.1** 兩個版本稱為 **Java 1**。 - **Java 1.2**、**1.3**、**1.4** 都稱為 **Java 2**,其中 **Java 2** 的最後一個版本是 **1.4.2**。 - **J2SE 5.0** 是 **Java 2** 平台的第五個版本,於 **2004** 年推出,之後改名為 **Java SE 5**。 - **Java SE 6** 於 **2006** 年推出,**Java SE 7** 於 **2011** 年推出, **Java SE 8** 於 **2014** 年推出,**Java SE 9** 於 **2017** 年推出, **Java SE 10** 於 **2018** 年推出,**Java SE 11** 於 **2018** 年推出, **Java SE 12** 於 **2019** 年推出,**Java SE 13** 於 **2019** 年推出, **Java SE 14** 於 **2020** 年推出,**Java SE 15** 於 **2020** 年推出 - **Java** 還有其他版本,例如 **Java ME(Java Micro Edition)** 和**Java EE(Java Enterprise Edition)** ,用於開發行動裝置和企業應用程式。 ## **Java語言特性** - **可攜帶性**:Java 程式會編譯成 **byte code (位元組碼)**,可以在任何安裝了 **Java Virtual Machine (JVM)** 的機器上運行,**不需要重新編譯**。 - **垃圾回收**:Java 語言提供自動回收垃圾記憶體的功能,**不需要**手動釋放記憶體。 - **物件導向**:Java 語言的設計核心是物件導向,所有的**程式都是由物件組成**,方便程式設計和維護。 - **多重繼承**:Java 語言**支援介面(interface)** 的**多重繼承**,但不支援**類(class)** 的**多重繼承**。 ## **Java程式類型** - **Java Application**:單獨運行在電腦 PC 上的 Java 程式。 - **Java Applet**:主要在 Web Page 網頁上的 Java 程式,現在已經不再被廣泛使用。 - **JavaScript**:不是 Java 程式,而是一種腳本語言,用於網頁前端開發。 - **Java Server Pages (JSP)**:在伺服器 Server 端所執行的 Java 語法的 Script 程式。 - **Android**:在 Android 作業系統執行的 Java 程式,現在已經不再使用 Java 語言,而是使用 Kotlin 或其他語言。 ## **Java開發環境** - **Java Software Development Kit (JDK)**:提供 Java 開發所需的**編譯器**、**除錯器**和**其他工具**,以及 **Java Runtime Environment (JRE)**。 - **Java Runtime Environment (JRE)**:只提供 Java 執行所需的環境,不包括**開發工具**。 ## **Java平台** Java 平台分為**三種**不同的版本: - **Java Standard Edition (Java SE) 基本版**,適用於桌面應用程式和一些簡單的伺服器應用程式。 - **Java Enterprise Edition (Java EE) 企業版**,包含 **Servlet**、**JSP**、**Java Beans** 等,適用於大型企業應用程式。 - **Java Micro Edition (Java ME) 迷你版**,適用於嵌入式裝置和行動裝置。 ## **其他關於JAVA知識** ### **物件導向** Java 的**物件導向設計**,可以讓程式開發更容易分工與協作, 並且可以撰寫出較易讓人理解的程式碼和文件。 以下是物件導向的一些基本概念: - **封裝 (Encapsulation)**:將屬性和方法封裝在一個類別中,只開放必要的介面給外部使用。 - **繼承 (Inheritance)**:子類別可以繼承父類別的屬性和方法,並且可以擴充或修改它們。 - **多型 (Polymorphism)**:同一個方法可以在不同的類別中有不同的實現方式。 ### **大型軟體開發** Java 的**物件導向設計**特性,適合用於**大型軟體開發**與分工。 開發人員可以將**不同的功能**模組化成**不同的類別**,並且可以透過**繼承**和**多型**等機制, 實現程式碼的重用和擴充。 --- # **類別(Class)** :::info Java 是一種物件導向的程式語言,使用 "**類別**" **(Class)** 來實作物件的概念。 每一個物件都是由一個類別所建立而成,這個類別定義了物件的屬性和方法。 ::: ## **定義類別** Java 中定義類別的方式如下: ```java= public class MyClass { // 定義類別的屬性和方法 } ``` 其中,**public** 是一個存取修飾詞,表示這個類別是**公開的**,可以在其他類別中被使用。 **MyClass** 則是類別的名稱,可以自行定義。 ## **程式的進入點** ### **說明** Java 程式的進入點是 main() 函數,程式從這裡開始執行。進入點的定義如下: ```java= public static void main(String[] args) { // 程式開始執行的地方 } ``` - `main`:進入點的函數名稱。一定要取名為 `main`。 - ``(String[] args)``:傳遞給 `main` 的參數。所有的宣告與名稱一定要如此寫。可以是任何數量的字串參數。 - `void`:`main` 的傳回值。`void` 代表不傳回任何值。 - `public`:允許任何 class 呼叫這個 main method。 - `{}`:將您想執行的程式填在此處。每行程式後方都要以分號 `;` 分開。 --- 在進入點中,可以呼叫其他方法或執行其他程式碼。 程式的執行順序是由進入點開始,往下依序執行每一行程式碼。 ### **範例** 以下是一個簡單的 main 方法範例: ```java= public class Main { public static void main(String[] args) { System.out.println("Hello, world!"); } } ``` 在進入點中,可以呼叫其他方法或執行其他程式碼。 # **變數(Variables)** :::info 變數是儲存資料的單位,每個變數都有各自的名稱與資料型態。 在 Java 中,變數必須先宣告才能使用。 ::: ## **變數宣告(Declaration)** 變數宣告的目的是告知電腦,程式中要使用哪些變數,並配置記憶體以供存放。 變數必須在第一次使用前宣告。 變數宣告的語法如下: ```java= DataType VarName [= Initial Value]; ``` - **DataType**:變數的資料型態,例如 `int`、`double` 等。 - **VarName**:變數的名稱,可以是任何合法的識別字,建議使用有意義的名稱。 - **Initial Value**:變數的初始值,可以省略不寫。 如果省略不寫,則變數的初始值為 `0`(數值類型)或 `null`(物件類型)。 以下是一個變數宣告的範例: ```java= int a = 24; double b; ``` 在這個範例中,我們宣告了兩個變數 `a` 和 `b`。 `a` 的資料型態為 `int`,初始值為 `24` `b` 的資料型態為 `double`,沒有初始值。 ## **變數命名規則** 在 Java 中,變數的命名規則如下: - 變數名稱**必須**以`字母`、`底線`或`$`開頭。 - 變數名稱**不能**以`數字`開頭。 - 變數名稱**只能**包含`字母`、`數字`、`底線`或`$`。 - 變數名稱**不能**是 Java 的保留字(例如 `int`、`double` 等)。 ## **資料型態** 以下這些基本資料型態是 Java 中最基本的資料型態,用來儲存各種不同的資料。 在宣告變數時,**必須**指定變數的**資料型態**。 ### **整數型態** :::info 整數型態用來儲存整數,包括`正整數`、`負整數`和`零`。 在 Java 中,整數型態包括 `byte`、`short`、`int` 和 `long` 四種。 ::: | 資料型態 | 描述 | 大小(位元組) | 範圍 | | --- | --- | --- | --- | | **byte** | `8` 位元的`有符號整數` | 1 | `-128` 到 `127` | | **short** | `16` 位元的`有符號整數` | 2 | `-32,768` 到 `32,767` | | **int** | `32` 位元的`有符號整數` | 4 |`-2,147,483,648` 到 `2,147,483,647` | | **long** | `64` 位元的`有符號整數` | 8 | `-9,223,372,036,854,775,808` 到 `9,223,372,036,854,775,807` | *宣告範本* ```java= byte b = 99; short s = 99; int i = 99; long l = 99L; ``` ### **浮點型態** :::info 浮點型態用來儲存浮點數,包括`正數`、`負數`和`零`。 在 Java 中,浮點型態包括 `float` 和 `double` 兩種。 ::: | 資料型態 | 描述 | 大小(位元組) | 範圍 | | --- | --- | --- | --- | | **float** | `單精度浮點數` | 4 | 大約 `±3.40282347E+38F`(有效位數為 `6`-`7` 位數) | | **double** | `雙精度浮點數` | 8 | 大約 `±1.79769313486231570E+308`(有效位數為 `15` 位數) | *宣告範本* ```java= float f = 1.234f; double d = 1.234; double d = 1.234d; ``` ### **字元型態** :::info 字元型態用來儲存單個字符,包括`字母`、`數字`、`符號`和`控制字符`。 在 Java 中,字元型態為 `char`。 ::: | 資料型態 | 描述 | 大小(位元組) | 範圍 | | --- | --- | --- | --- | | **char** | 單個 `16` 位元的 `Unicode 字元` | 2 | `0` 到 `65,535` | *宣告範本* ```java= char c = 'a'; ``` ### **布林型態** :::info 布林型態用來儲存布林值,只有兩種值:`true` 和 `false`。在 Java 中, 布林型態為 `boolean`。 ::: | 資料型態 | 描述 | 大小(位元組) | 範圍 | | --- | --- | --- | --- | | **boolean** | 僅有兩個值:`true` 或 `false` | 1 | `-` | *宣告範本* ```java= boolean b = true; ``` ## **溢位(Overflow)** 是一種當數值超過資料型態範圍的錯誤。 在 Java 中,每種資料型態都有其範圍限制,如果資料型態無法容納某個數值, 則會發生溢位錯誤。溢位錯誤可能會導致程式產生不正確的結果, 因此在實際開發中應該避免使用可能導致溢位的操作。 以下是各種資料型態的範例程式,用來示範溢位錯誤: ```java= // byte 溢位 byte b = 127; b++; System.out.println(b); // -128 // short 溢位 short s = 32767; s++; System.out.println(s); // -32768 // int 溢位 int i = 2147483647; i++; System.out.println(i); // -2147483648 // long 溢位 long l = 9223372036854775807L; l++; System.out.println(l); // -9223372036854775808 // float 溢位 float f = Float.MAX_VALUE; f *= 2; System.out.println(f); // Infinity // double 溢位 double d = Double.MAX_VALUE; d *= 2; System.out.println(d); // Infinity ``` 在這些範例中,我們使用了各種資料型態的最大值,然後將其加上 `1` 或乘以 `2`,以引發溢位錯誤。 當發生溢位時,資料型態的值會從最大值變成最小值,或從最小值變成最大值,因此會產生不正確的結果。 在實際開發中,我們應該避免使用可能導致溢位的操作,以確保程式的正確性。 ## **常數(constant)** 在 Java 中,常數是指在程式執行過程中其值不會改變的變數。 可以使用 `final` 關鍵字來聲明一個常數。常數的語法如下: ```java= final DataType VarName = InitialValue; ``` :::info `DataType` 是變數的資料型別,`VarName` 是變數的名稱,`InitialValue` 是變數的初始值。 ::: --- 一旦一個變數被聲明為 final,其值將不可再更改。 如果程式碼試圖更改一個 final 變數的值,將會在編譯時期產生錯誤(compile-time error)。 以下是一個常數的範例: ```java= final double PI = 3.1415; ``` :::info 在這個範例中,`PI` 被聲明為一個 final 變數,其值為 `3.1416`。 由於 `PI` 是一個常數,所以在程式執行過程中其值不會改變。 ::: --- 如果程式碼試圖更改 `PI` 的值,例如: ```java= final double PI = 3.1415; PI = 5.4321; ``` :::danger 則會在編譯時期產生錯誤。 ::: --- 需要補充的是,Java 中的常數通常使用**全部大寫字母**表示,並使用**底線分隔單詞**, 例如 `CURRENT_USER_NUM`。 此外,常數的命名應該具有**描述性**,以便於程式碼的閱讀和理解。 # **運算子(Operator)** :::info 運算子是在程式語言中用來執行特定操作的符號或關鍵字, 例如數學運算、邏輯運算、位元運算等。 每一種運算子都有其特定的功能和用法,並且可以應用在不同的資料型別上。 ::: ## **類型** Java 中的運算子可對一個、兩個或三個運算元執行動作。 依照所需運算元數目,運算子可分為以下**三種**: - 一元運算子:只需要**一**個運算元,對變數進行**遞增/遞減**操作, 例如 `a++`、`--a`。 - 二元運算子:需要**兩**個運算元,將**右邊**的運算元**賦值**給**左邊**的運算元, 例如 `a = 99`。 - 三元運算子:需要**三**個運算元,語法為 `(condition) ? expression1 : expression2`, 其中 `condition` 為條件,如果條件成立,則回傳 `expression1` 的值, 否則回傳 `expression2` 的值,例如 `(a>0) ? a-1 : (a+1)`。 依照運算子擺放位置,運算子可分為以下**三種**: - 前置運算子:運算子擺放在運算元之**前**,例如 `++i`。 - 後置運算子:運算子擺放在運算元之**後**,例如 `i++`。 - 中置運算子:運算子擺放在**中間**,例如 `a + b`。 ### **算術運算子** #### *單一運算子* | 運算子 | 用法 | 說明 | | --- | --- | --- | | + | +a | 表示正 a | | - | -a | 表示負 a | | ! | !a | 表示邏輯非,將 a 的值取反 | | ~ | ~a | 表示位元反轉,將 a 的二進位表示法的每個位元取反 | | ++ | a++ 或 ++a | 表示將 a 的值加 1,若放在 a 的後面則先回傳 a 的值再加 1,若放在 a 的前面則先加 1 再回傳 a 的值 | | -\- | a-- 或 --a | 表示將 a 的值減 1,若放在 a 的後面則先回傳 a 的值再減 1,若放在 a 的前面則先減 1 再回傳 a 的值 | #### *二元運算子* | 運算子 | 用法 | 說明 | | --- | --- | --- | | + | a + b | a 加上 b | | - | a - b | a 減去 b | | * | a * b | a 乘上 b | | / | a / b | a 除以 b | | % | a % b | a 除以 b 的餘數 | ### **指定運算子** | 運算子 | 用法 | 說明 | | --- | --- | --- | | = | a = b | 將 b 的值賦給 a | | += | a += b | 將 a 加上 b 的值後再賦給 a | | -= | a -= b | 將 a 減去 b 的值後再賦給 a | | \*= | a \*= b | 將 a 乘上 b 的值後再賦給 a | | /= | a /= b | 將 a 除以 b 的值後再賦給 a | | %= | a %= b | 將 a 除以 b 的餘數再賦給 a | ### **關係運算子** | 運算子 | 用法 | 說明 | | --- | --- | --- | | == | a == b | 判斷 a 是否等於 b,若成立則回傳 true,否則回傳 false | | != | a != b | 判斷 a 是否不等於 b,若成立則回傳 true,否則回傳 false | | < | a < b | 判斷 a 是否小於 b,若成立則回傳 true,否則回傳 false | | <= | a <= b | 判斷 a 是否小於等於 b,若成立則回傳 true,否則回傳 false | | > | a > b | 判斷 a 是否大於 b,若成立則回傳 true,否則回傳 false | | >= | a >= b | 判斷 a 是否大於等於 b,若成立則回傳 true,否則回傳 false | ### **條件運算子** | 運算子 | 用法 | 說明 | | --- | --- | --- | | && | a && b | 邏輯 AND,若 a 和 b 都成立則回傳 true,否則回傳 false | | \|\| | a \|\| b | 邏輯 OR,若 a 或 b 有一個成立則回傳 true,否則回傳 false | ### **邏輯運算子** | 運算子 | 用法 | 說明 | | --- | --- | --- | | ! | !a | 表示邏輯非,將 a 的布林值取反 | | & | a & b | 位元 AND,將 a 和 b 的二進位表示法進行 AND 運算 | | \| | a \| b | 位元 OR,將 a 和 b 的二進位表示法進行 OR 運算 | | ^ | a ^ b | 位元 XOR,將 a 和 b 的二進位表示法進行 XOR 運算 | ### **位元運算子** | 運算子 | 用法 | 說明 | | --- | --- | --- | | << | a << b | 左位移,將 a 的二進位表示法向左移動 b 個位元 | | >> | a >> b | 右位移,將 a 的二進位表示法向右移動 b 個位元 | | >>> | a >>> b | 無符號右位移,將 a 的二進位表示法向右移動 b 個位元,左邊空出的位元以 0 填補 | ### **進階指定運算子** | 運算子 | 用法 | 說明 | | --- | --- | --- | | &= | a &= b | 將 a 和 b 的二進位表示法進行 AND 運算後再賦給 a | | \|= | a \|= b | 將 a 和 b 的二進位表示法進行 OR 運算後再賦給 a | | ^= | a ^= b | 將 a 和 b 的二進位表示法進行 XOR 運算後再賦給 a | | <<= | a <<= b | 將 a 的二進位表示法向左移動 b 個位元後再賦給 a | | >>= | a >>= b | 將 a 的二進位表示法向右移動 b 個位元後再賦給 a | | >>>= | a >>>= b | 將 a 的二進位表示法向右移動 b 個位元,左邊空出的位元以 0 填補後再賦給 a | ### **特殊運算子** | 運算子 | 用法 | 說明 | | --- | --- | --- | | ?: | a ? b : c | 條件運算子,若 a 成立則回傳 b,否則回傳 c | | , | a, b | 逗號運算子,先執行 a,再執行 b,最後回傳 b 的值 | | [] | a[0] | 存取陣列元素的方式,其中 a 是一個陣列,而 [0] 表示要存取第一個元素。例如,如果 a 是 [1, 2, 3],那麼 a[0] 就是 1。 | | . | Object.Property | 存取物件屬性的方式,其中 Object 是一個物件,而 Property 是一個屬性名稱。例如,如果有一個物件 person,其中有一個屬性 name,那麼可以使用 **person**.name 來存取這個屬性的值。 | | (type) | (int) 3.5 | 強制轉型的方式,其中 (int) 表示要將後面的值轉型為整數型別,而 3.5 則是一個浮點數值。例如,如果要將 3.5 強制轉型為整數,那麼會得到 3。 | | new | new Object() | 建立物件的方式,其中 new 是一個關鍵字,而 Object() 則是一個物件類別的建構函式。例如,如果有一個物件類別 Person,那麼可以使用 new Person() 來建立一個新的 Person 物件。 | | (param, param, …) | f(X, Y, Z) | 呼叫函式的方式,其中 f 是一個函式名稱,而 X、Y 和 Z 則是傳給函式的參數。例如,如果有一個函式 add(x, y),那麼可以使用 add(2, 3) 來呼叫這個函式,並回傳 5。 | ### **運算子優先度** |優先度| 類別 | 運算子 | | --- | --- | --- | | 0 | 分隔運算子 | `()` `[]` `{}` `,` `.` | | 1 | 單一運算子 | `+` `-` `!` `~` `++` `--` | | 2 | 指定運算子 | `=` `+=` `-=` `*=` `/=` `%=` `&=` `\|=` `^=` `<<=` `>>=` `>>>=` | | 3 | 關係運算子 | `==` `!=` `<` `<=` `>` `>=` | | 4 | 條件運算子 | `&&` `\|\|` | | 5 | 位元運算子 | `&` `\|` `^` `<<` `>>` `>>>` | # **程式區塊(Blocks)** :::info 程式區塊是以 `{}` 大括號包覆而成,可以內含零個或以上的敘述。 通常在條件判斷語句中使用,例如 **if 判斷句**,若條件成立,就會執行 `{}` 內包含的敘述, 否則略過。在許多程式語言中,程式區塊還會配合分號 `;` 結束敘述,確保程式碼的正確執行。 ::: **範例:** ```java= if (a > 2) { // 如果 a 大於 2,則執行以下程式區塊內的敘述 System.out.println("a is greater than 2."); } else { // 如果 a 小於等於 2,則執行以下程式區塊內的敘述 System.out.println("a is less than or equal to 2."); } ``` 在程式區塊的 `{}` 內也可以包含其他的程式區塊, 例如**多層迴圈**、**巢狀**的**if 判斷**等等,只要在不同層次的程式區塊中使用不同的變數名稱, 即可避免變數名稱衝突的問題。 # **程式流程(Program-flow)** :::info 程式可以使用結構化的方式來表達流程,讓程式碼更易讀、易維護 ::: ## **循序結構** 循序結構是程式中最簡單的結構之一,它**按照順序執行敘述**,從上到下按照程式碼的順序執行,沒有任何的分支或迴圈。 ```java= int a = 1; int b = 2; int c = a + b; System.out.println(c); ``` ## **選擇結構** 選擇結構基於條件來決定程式的執行路徑,當條件滿足時執行 `A 敘述`,否則執行 `B 敘述`。 下面是一個簡單的 `if-else` 選擇結構的例子: ```java= int x = 10; if (x > 0) { System.out.println("x 是一個正數"); } else { System.out.println("x 不是一個正數"); } ``` ## **重複結構** 重複結構可以讓程式重複執行某些敘述,以達到簡化程式碼的目的。 下面是一個簡單的 `while` 迴圈重複結構的例子: ```java= int i = 0; while (i < 5) { System.out.println(i); i++; } ``` 此迴圈會進行 `5` 次迴圈,每次迴圈都會把目前的數字印出來,直到迴圈次數到達 `5` 次為止。 # **基本語法(Basic)** :::info 💡 開始寫程式囉 ::: ## **if-else和switch** `if-else` 和 `switch` 都是在程式中用來進行調條件的判斷的關鍵字。 ### **if-else** `if-else` 在判斷條件成立時執行一段程式碼,反之則執行另外一段程式碼。 ```java= if (score >= 60) { System.out.println("pass"); } else { System.out.println("fail"); } ``` ### **switch** `switch` 在判斷某個變數的值時,可以根據不同的值執行對應的程式碼。 ```java= switch (keyCode) { case 37: moveLeft(); break; case 38: moveUp(); break; case 39: moveRight(); break; case 40: moveDown(); break; default: System.out.println("invalid key"); break; } ``` ## **輸入(Input)** :::success 在`Java`中,`Scanner`是一個用於讀取**使用者輸入**的類別。 使用`Scanner`,你可以輕鬆地從控制台讀取**使用者輸入**的資料。 ::: 使用`java.util.Scanner`類別來讀取使用者從控制台輸入的資料。 創建一個`Scanner物件`,然後使用`nextInt()`方法讀取**使用者輸入**的整數。 ```java= import java.util.Scanner; public class ScannerExample { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("請輸入一個整數:"); int num = scanner.nextInt(); System.out.println("你輸入的整數是:" + num); scanner.close(); } } ``` 你可以使用不同的方法來讀取不同類型的輸入, 例如`nextDouble()`、`nextLine()`等。 **記得在使用完`Scanner`後關閉它,以避免資源泄漏**。 ## **輸出(Output)** :::success 在Java中,你可以使用`System.out.println()`或`System.out.print()`方法來輸出這些訊息。 ::: `System.out.println()`:會在輸出結束時自動換行 ```java= System.out.println("Hello, World!"); ``` 輸出結果: ```bash Hello, World! ``` --- `System.out.print()`:方法則不會 ```java= System.out.print("Hello, "); System.out.print("World!"); ``` 輸出結果: ```bash Hello, World! ``` `System.out.println()`和`System.out.print()`方法是Java中常用的輸出方法, 它們可以幫助你將訊息輸出到控制台上,並根據需要換行或不換行。