學習-Java順序結構之字元變換之大小寫字母轉換

风之弋然發表於2024-04-01

任務描述

本關任務:將鍵盤輸入的大寫字母轉化為小寫字母。

相關知識

為了完成本關任務,你需要掌握:

  1. 字元型變數和常量;
  2. 字元型資料的加減運算;
  3. 字元型資料的輸入/輸出。
字元型變數和常量

在之前我們學習了整型和浮點型的變數和常量,接下來介紹字元型的變數和常量。

首先我們要先了解一下什麼是字元,我們之前學過 Unicode 字符集,這裡的字元值的就是 Unicode 字符集中的字元。

字元型常量

字元常量,用單引號引用起來的的單個字元,就叫字元常量,例如:'w','2','R' 等。

例子:

  1. public class Demo {

  2. `public static void main(String[] args) {`
    
  3.     `// 單引號裡面是字元常量,裡面的內容不可以為空,必須是一個字元,不可以是兩個或多個。`
    
  4.     `System.out.println('q');`
    
  5.     `System.out.println('漢');`
    
  6. `}`
    
  7. }

字元型變數

Java 中的字元型變數型別為 char ,它是一個單一的兩個位元組的 16 位 Unicode 字元;最小值是 \u0000(即為 0 );最大值是 \uffff(即為 65535 );預設值為空;用單引號引起來的部分;它可以儲存任何字元,示例如下:

  1. // 宣告一個變數名為 a,資料型別為 char 的變數,並賦予該變數的值為 A
  2. char a = 'A';
  3. // 宣告一個變數名為 b,資料型別為 byte 的變數,並賦予該變數的值為 漢
  4. char b = '漢';
  5. // 輸出 a,b 兩個變數
  6. System.out.println(a);
  7. System.out.print(b);

執行結果如下:

  1. A
字元運算

字元型別是可以運算的,因為字元在 ASCII 等字元編碼表中有對應的數值。在 Java 中,對字元型字元執行時,直接當做 ASCII 表對應的整數來對待。

示例:

  1. // 定義一個字元型變數a,值為 a
  2. char a = 'a';
  3. // 定義一個字元型變數b,值為 b
  4. char b = 'b';
  5. // 定義一個字元型變數c,值為 中
  6. char c = '中';
  7. // 定義一個字元型變數d,值為 國
  8. char d = '國';
  9. // 字元之間運算,型別會提升為 int 型別
  10. int m = a + b; // 計算 a+b 的值
  11. System.out.println(a);
  12. int n = a - b; // 計算 a-b 的值
  13. System.out.println(b);
  14. System.out.print(c+d);

執行結果:

  1. 195
  2. -1
  3. 42282

我們發現字元之間運算,型別會提升為 int 型別,而如果我們並不想輸出它的 ASCII 碼的值,而是想要輸出它對應的字元該怎麼辦呢?

我們可以將 int 型別強制轉換為 char,當我們想要將一個大範圍的資料型別轉換為小範圍的資料型別,我們需要進行強制轉換。在後面的學習任務中,我們會為大家詳細介紹強制轉換。

  1. // 定義一個字元型變數a,值為 a;
  2. char a = 'a';
  3. // 將 int 型別強制轉化為 char 型。
  4. char m = (char)(a - 32);
  5. // 定義一個字元型變數c,值為 中;
  6. char c = '中';
  7. // 定義一個字元型變數d,值為 國;
  8. char d = '國';
  9. // 將 int 型別強制轉化為 char 型。
  10. char n = (char)(c+d);
  11. System.out.println(m);
  12. System.out.print(n);

執行結果:

  1. A

我們可以看到 a-32 結果為 A,這是為什麼呢?

因為字元 char 採用的是 Unicode 編碼的 16 位字元型別,其表示範圍是 0-65536。標準的 8 位 ASCII 字符集是 Unicode 的子集,其取值範圍為 0-127。大小寫字母之間正好相差 32。

當然,我們還要注意的是字串常量之間的加減運算並不需要強制轉換,但是我們要注意,當它結果超出 char 的範圍後會溢位。

  1. char m = 'a' - 32;
  2. System.out.print(m);

執行結果:

  1. A

字元運算我們已經有了一定的瞭解,那字元的輸入輸出又是怎樣的呢?

字元輸入輸出

在之前我們學習了整型和浮點型的輸入,那我們接著來看字元型的輸入輸出。

它與整型和浮點型都是透過例項一個 Scanner 物件來使用,字元型是呼叫reader.next().charAt(0)方法來獲取鍵盤輸入的字元。charAt(0)括號中的引數可以不為 0 ,在後期的學習任務中我們會為大家詳細介紹。

  1. import java.util.Scanner;

  2. public class Demo{

  3. `public static void main(String[] args) {`
    
  4.     `// 第一步:建立一個Scanner的例項物件,命名為reader`
    
  5.     `Scanner reader = new Scanner(System.in);`
    
  6.     `// 從鍵盤處接收使用者輸入的字元型資料`
    
  7.     `char a= reader.next().charAt(0);`
    
  8.     `System.out.print(a);`
    
  9. `}`
    
  10. }

使用者鍵盤輸入:a

執行結果:

  1. a

這就是如何獲取鍵盤輸入字元型資料的操作了,那我們接下來學習如何輸出字元型資料。

我們之前學到的System.out.print()System.out.println(),對於輸出字元型資料與輸出整型與字元型都是一樣的。

例子:

  1. char a = '中';
  2. char b = '國';
  3. System.out.println(a)
  4. System.out.print(b);

執行結果:

接下來我們來看格式化輸出字元型資料。輸出整型用的符號是 %d,而浮點型是 %f,那字元型是什麼呢?

%c 是格式化輸出字元型符號,來看一個例子。

  1. char d = '漢'
  2. System.out.printf("我是%c族人",d);

執行結果:

  1. 我是漢族人

程式設計要求

仔細閱讀右側編輯區內給出的程式碼框架及註釋,按照提示編寫程式程式碼。

測試說明

平臺將使用測試集執行你編寫的程式程式碼,若全部的執行結果正確,則通關。 可在右側“測試結果”區檢視具體的測試集詳情。

編寫程式碼

/**

 * 任務:將鍵盤輸入的字元轉化為小寫字母。

 * 類名為:LowerCase

 */

  

import java.util.Scanner;

  

public class LowerCase {

    public static void main(String[] args) {

        Scanner reader = new Scanner(System.in);

        /********** Begin **********/

        // 第一步:獲取鍵盤輸入的值

        char uppercaseChar = reader.next().charAt(0);

  

        // 第二步:將獲取到的大寫字母轉化為小寫字母

        char lowercaseChar = Character.toLowerCase(uppercaseChar);

  

        // 第三步:不換行輸出轉化後的小寫字母

        System.out.print(lowercaseChar);

        /********** End **********/

  

        reader.close();

    }

}

程式碼分析

當初學習程式設計時,理解程式碼中使用的各種概念和語法是很重要的。讓我們逐步分析這段程式碼:

  1. 匯入 Scanner 類

    import java.util.Scanner;
    

    這行程式碼匯入了 Java 標準庫中的 Scanner 類,它使我們能夠從標準輸入(通常是鍵盤)中讀取使用者的輸入。

  2. 定義 LowerCase 類

    public class LowerCase {
    

    這行程式碼定義了一個名為 LowerCase 的 Java 類,類名的首字母大寫是因為在 Java 中類名通常以大寫字母開頭。

  3. 定義 main 方法

    public static void main(String[] args) {
    

    這行程式碼定義了 Java 應用程式的入口點,即 main 方法。在 Java 程式中,main 方法是程式的起點,程式將從這裡開始執行。

  4. 建立 Scanner 物件

    Scanner reader = new Scanner(System.in);
    

    這行程式碼建立了一個名為 readerScanner 物件,它將從標準輸入流(System.in)中讀取使用者的輸入。

  5. 獲取鍵盤輸入的字元

    char uppercaseChar = reader.next().charAt(0);
    

    這行程式碼透過 Scanner 物件 reader 獲取了使用者輸入的下一個字串,並使用 charAt(0) 方法獲取該字串的第一個字元,並將其儲存在 uppercaseChar 變數中。

  6. 轉換大寫字母為小寫字母

    char lowercaseChar = Character.toLowerCase(uppercaseChar);
    

    這行程式碼使用 Character.toLowerCase() 方法將大寫字母轉換為小寫字母,並將結果儲存在 lowercaseChar 變數中。

  7. 輸出轉換後的小寫字母

    System.out.print(lowercaseChar);
    

    這行程式碼使用 System.out.print() 方法將轉換後的小寫字母輸出到標準輸出(通常是控制檯)上。

  8. 關閉 Scanner 物件

    reader.close();
    

    這行程式碼關閉了 Scanner 物件 reader,釋放了與其關聯的資源。

這段程式碼主要涉及了基本的輸入輸出、字串操作、字元操作等基礎知識。

擴充

類 與類方法

Character 類

當然,讓我們來了解一下 Character 類的一些常用方法。Character 類提供了一系列靜態方法來處理字元資料,這些方法允許你執行各種字元操作,比如大小寫轉換、字元型別判斷等等。

下面是 Character 類的一些常用方法:

  1. isLetter(char ch):判斷指定字元是否為字母。

    char ch = 'A';
    boolean isLetter = Character.isLetter(ch); // 返回 true
    
  2. isDigit(char ch):判斷指定字元是否為數字。

    char ch = '5';
    boolean isDigit = Character.isDigit(ch); // 返回 true
    
  3. isUpperCase(char ch):判斷指定字元是否為大寫字母。

    char ch = 'A';
    boolean isUpperCase = Character.isUpperCase(ch); // 返回 true
    
  4. isLowerCase(char ch):判斷指定字元是否為小寫字母。

    char ch = 'a';
    boolean isLowerCase = Character.isLowerCase(ch); // 返回 true
    
  5. toUpperCase(char ch):將指定字元轉換為大寫形式。

    char ch = 'a';
    char upperCaseChar = Character.toUpperCase(ch); // 返回 'A'
    
  6. toLowerCase(char ch):將指定字元轉換為小寫形式。

    char ch = 'A';
    char lowerCaseChar = Character.toLowerCase(ch); // 返回 'a'
    
  7. toString(char ch):將指定字元轉換為字串。

    char ch = 'A';
    String str = Character.toString(ch); // 返回 "A"
    
  8. getNumericValue(char ch):獲取指定字元的數值。

    char ch = '5';
    int numericValue = Character.getNumericValue(ch); // 返回 5
    

這些方法可以幫助你對字元進行各種常見操作,包括判斷字元的屬性、轉換字元的大小寫以及獲取字元的數值等。透過熟練運用這些方法,你可以更方便地處理字元資料。

Scanner 類

Scanner 類提供了許多常用的方法,用於從輸入流中讀取資料。下面是一些 Scanner 類的常用方法:

  1. next():讀取輸入的下一個單詞(以空白字元分隔)並返回字串。

    Scanner scanner = new Scanner(System.in);
    String word = scanner.next();
    
  2. nextInt():讀取輸入的下一個整數,並返回 int 型別的值。

    Scanner scanner = new Scanner(System.in);
    int number = scanner.nextInt();
    
  3. nextDouble():讀取輸入的下一個雙精度浮點數,並返回 double 型別的值。

    Scanner scanner = new Scanner(System.in);
    double value = scanner.nextDouble();
    
  4. nextLine():讀取輸入的下一行,並返回字串,不包括換行符。

    Scanner scanner = new Scanner(System.in);
    String line = scanner.nextLine();
    
  5. hasNext():檢查輸入中是否還有下一個單詞(以空白字元分隔),返回 truefalse

    Scanner scanner = new Scanner(System.in);
    boolean hasNext = scanner.hasNext();
    
  6. hasNextInt():檢查輸入中是否還有下一個整數,返回 truefalse

    Scanner scanner = new Scanner(System.in);
    boolean hasNextInt = scanner.hasNextInt();
    
  7. hasNextLine():檢查輸入中是否還有下一行,返回 truefalse

    Scanner scanner = new Scanner(System.in);
    boolean hasNextLine = scanner.hasNextLine();
    
  8. useDelimiter(String pattern):設定用於分隔標記的模式字串。預設情況下,空白字元用作分隔符。

    Scanner scanner = new Scanner(System.in);
    scanner.useDelimiter(",");
    

這些方法使得從不同型別的輸入流(如標準輸入、檔案、字串等)中讀取資料變得非常方便。透過適當地使用這些方法,你可以輕鬆地處理各種輸入資料。


Java基礎


訪問修飾符

  Java 中有多種訪問修飾符,它們決定了類、變數、方法或建構函式的訪問許可權。Java 中的訪問修飾符包括以下幾種:

  1. public:表示對所有類都是可見的。即使是不同包中的類,只要是 public 訪問修飾符修飾的成員,都可以被訪問。

  2. protected:表示對同一包中的類以及所有子類都是可見的。如果子類和父類不在同一個包中,那麼子類只能訪問 protected 修飾的成員,而不能訪問父類中預設訪問許可權和 private 訪問許可權修飾的成員。

  3. 預設(package-private):如果沒有使用任何訪問修飾符(即不寫任何修飾符),則表示該成員具有包級別的訪問許可權,即對同一包中的所有類是可見的。

  4. private:表示只有在同一類中才可以訪問。私有成員對類的使用者是隱藏的,類的使用者無法直接訪問私有成員,而必須透過類提供的公共方法來訪問私有成員。

這些訪問修飾符允許你控制類的成員對其他類的可見性,從而實現封裝、繼承和多型等物件導向程式設計的特性。


定義方法的關鍵字

當定義一個方法時,你可以使用不同的關鍵字來指定方法的行為和特性。下面是每個關鍵字的詳細解釋:

  1. public

    • 這個關鍵字表示方法對所有類都是可見的。
    • 其他類可以訪問公共方法,從而呼叫它們。
    • 通常在需要提供給其他類使用的方法上使用 public
  2. protected

    • 這個關鍵字表示方法對同一包中的類以及所有子類可見。
    • 只有在同一包中或子類中才能訪問受保護的方法。
    • 通常在需要在繼承層次結構中提供訪問許可權的方法上使用 protected
  3. private

    • 這個關鍵字表示方法只對同一類中可見。
    • 其他類無法直接訪問私有方法。
    • 通常在只在當前類內部使用的輔助方法上使用 private
  4. abstract

    • 這個關鍵字表示方法沒有實現,需要在子類中被覆蓋。
    • 抽象方法沒有方法體,只有方法簽名。
    • 抽象方法必須在抽象類中宣告,而抽象類本身可以有抽象方法和具體方法。
  5. final

    • 這個關鍵字表示方法不能被子類重寫。
    • 如果一個類被宣告為 final,則其中的所有方法都自動成為 final 方法,無法被子類修改。
  6. static

    • 這個關鍵字表示方法屬於類而不是例項,可以透過類名直接呼叫。
    • 靜態方法在記憶體中只有一份複製,被所有例項共享。
    • 靜態方法不能訪問非靜態的例項變數和例項方法,只能訪問靜態變數和靜態方法。
  7. synchronized

    • 這個關鍵字表示方法是同步的,只能被一個執行緒訪問。
    • 同步方法在多執行緒環境中用於防止競態條件和資料不一致性。
    • 只能在例項方法上使用 synchronized,不能在靜態方法上使用。

根據你的需求,選擇適當的關鍵字來定義方法,以確保程式碼的可維護性、可讀性和安全性。


例項和類

進一步解釋一下例項(instance)和類(class)的概念。

在物件導向程式設計中,類是一種抽象的概念,它描述了具有相同屬性和行為一組物件的模板。類定義了物件的結構和行為,但它本身並不佔用記憶體空間

例項則是類的具體化,是根據類建立的物件。當你建立一個類的例項時,會分配記憶體空間來儲存該物件的屬性和方法。每個例項都有自己的屬性值,但它們共享相同的類結構和行為。

例如,假設我們有一個名為 Car 的類,它描述了汽車的屬性和行為,比如顏色、型號、加速和剎車等。當我們建立一個具體的汽車物件時,比如一輛紅色的奧迪車,這個物件就是 Car 類的一個例項。

現在來解釋 static 關鍵字的含義:當我們將方法宣告為 static 時,它意味著這個方法不再屬於某個特定的例項,而是屬於整個類。換句話說,無論有多少個類的例項被建立,static 方法在記憶體中只有一份複製,被所有例項共享。

因此,static 方法可以直接透過類名呼叫,而不需要透過例項。這使得靜態方法在不需要例項的情況下也可以被呼叫,非常適合用於實現通用的工具方法或單例模式等場景。


靜態方法與例項方法

實際上,Java 中並沒有 "動態方法" 這個概念。你可能是混淆了 "靜態方法" 和 "例項方法"。

  • 靜態方法:在記憶體中只有一份複製,被所有例項共享。無論建立了多少個類的例項,靜態方法都只存在一份。靜態方法可以直接透過類名呼叫,而不需要建立類的例項。

  • 例項方法:每個類的例項都有自己的複製。當建立一個類的例項時,例項方法會被分配到該例項所佔據的記憶體中。每個例項都有自己的方法副本,它們不會被其他例項共享。

因此,靜態方法和例項方法的區別在於是否與類的例項相關。靜態方法獨立於類的任何例項,而例項方法與每個類的例項相關聯。

靜態方法不能訪問非靜態的例項變數和例項方法,只能訪問靜態變數和靜態方法。為什麼?

靜態方法是類級別的方法,它們在記憶體中只有一份複製,被所有類的例項共享。由於靜態方法不與任何特定的例項相關聯,因此它們無法訪問例項級別的變數和方法。

考慮到以下幾點:

  1. 記憶體分配靜態方法在類載入時就已經被分配記憶體空間,而例項變數和例項方法是在建立物件例項時才會被分配記憶體空間。 因此,當靜態方法被呼叫時,可能還沒有任何例項被建立,因此無法訪問例項級別的成員。

  2. 例項變數和例項方法需要特定的物件上下文:例項變數和例項方法是與特定的物件例項相關聯的,它們需要透過物件引用來訪問。 而靜態方法沒有這種物件上下文,無法直接訪問例項級別的成員。

  3. 避免歧義:如果靜態方法可以訪問例項級別的成員,可能會導致歧義和混亂。因為靜態方法屬於類,而例項變數和例項方法屬於物件例項,如果靜態方法可以訪問例項級別的成員,可能會使得程式碼邏輯不清晰,難以理解。

因此,為了保持程式碼的清晰性、簡潔性和可維護性,Java 設計者規定靜態方法只能訪問靜態變數和靜態方法,而不能訪問例項變數和例項方法。


類本身不佔記憶體空間?為什麼靜態方法在類載入時就已經被分配記憶體空間,那不就是類佔了記憶體空間

你提出了一個很好的問題,讓我更清楚地解釋一下:

在Java中,類本身確實是不會佔用記憶體空間的。當JVM載入類時,會建立一個類的物件,稱為類物件(Class Object),用於表示這個類的結構資訊和方法程式碼。這個類物件包含了類的方法程式碼,包括靜態方法。

靜態方法被儲存在類物件中,這意味著它們在記憶體中只有一份複製,與任何特定的例項無關。當類載入時,類物件被建立並放入方法區(Method Area)中,靜態方法也隨之載入到記憶體中,但它們不會隨著每個例項的建立而複製

類物件本身佔用的記憶體空間相對較小,主要用於儲存類的結構資訊,例如類名、方法簽名、常量池等。這個過程與例項建立時所需的記憶體空間是不同的。例項在堆記憶體中分配空間,它們包含了例項變數的值以及對方法的引用。

因此,雖然類物件會佔用一些記憶體空間,但這個記憶體空間相對較小,並且是共享的,與例項的建立數量無關。而靜態方法被儲存在類物件中,因此在類載入時就已經被分配記憶體空間,但這並不意味著類的例項被建立了。


物件上下文

"物件上下文" 是指在物件導向程式設計中,方法執行時所處的特定物件的環境或狀態。 換句話說,它是指方法被呼叫時所關聯的物件及其屬性和方法。

在 Java 中,每個物件都有自己的狀態(即例項變數的值)和行為(即方法)。當呼叫物件的方法時,這個方法會在該物件的上下文中執行。在方法執行期間,方法可以訪問並操作物件的屬性,以及呼叫物件的其他方法。

例如,假設有一個 Car 類,它有一個 drive() 方法。當你呼叫 drive() 方法時,它會在特定的汽車物件上執行。在方法執行期間,drive() 方法可以訪問該汽車物件的屬性(如速度、方向等)並執行相應的操作。

因此,"物件上下文" 表示方法執行時所處的特定物件的環境,它確定了方法可以訪問的屬性和方法,以及方法的行為和結果。


返回型別

好的,讓我詳細介紹每種方法返回型別以及對應的關鍵字:

  1. 基本資料型別

    • 型別:基本資料型別是 Java 中最基本的資料型別,包括整型、浮點型、字元型和布林型。

    • 關鍵字

      • int:表示整型資料,範圍為 -2147483648 到 2147483647。
      • double:表示雙精度浮點型資料,範圍為 -1.7976931348623157 x 10^308 到 1.7976931348623157 x 10^308。
      • float:表示單精度浮點型資料,範圍為 -3.4028235 x 10^38 到 3.4028235 x 10^38。
      • char:表示字元資料,用單引號表示,如 'A'
      • boolean:表示布林型資料,只能是 truefalse
  2. 引用資料型別

    • 型別:引用資料型別是指向物件的引用,包括類、介面和陣列。

    • 關鍵字

      • 類:自定義的類,使用類名錶示。
      • 介面:使用介面名錶示。
      • 陣列:使用資料型別後加方括號 [] 表示,例如 int[]String[]
  3. 特殊型別

    • 型別:特殊型別包括 void、泛型型別和列舉型別。

    • 關鍵字

      • void:表示方法沒有返回值。
      • 泛型型別:根據需要指定泛型的具體型別,例如 ArrayList<String>Map<Integer, String>
      • 列舉型別:使用關鍵字 enum 來定義列舉型別,例如 enum Day {MONDAY, TUESDAY, WEDNESDAY}
  4. 其他型別

    • 型別:其他型別包括 long、short、byte、String 和 Object 等。

    • 關鍵字

      • long:表示長整型資料,範圍為 -9223372036854775808 到 9223372036854775807。
      • short:表示短整型資料,範圍為 -32768 到 32767。
      • byte:表示位元組資料,範圍為 -128 到 127。
      • String:表示字串,用雙引號表示,例如 "Hello"
      • Object:表示任意物件型別,所有類都是 Object 類的子類。

這些就是 Java 中常見的方法返回型別及其關鍵字的詳細介紹。在編寫方法時,根據方法的功能和需要返回的資料型別,選擇合適的返回型別和關鍵字。


返回引用資料型別解析

在 Java 中,方法確實可以返回引用資料型別,也就是返回物件的引用。這意味著方法返回的是指向物件的引用,而不是物件本身的複製。以下是一個示例:

public class Example {
    public static void main(String[] args) {
        // 呼叫方法,獲取物件引用
        MyClass obj = getObject();
        
        // 使用返回的物件引用
        obj.method();
    }
    
    // 返回引用資料型別的方法
    public static MyClass getObject() {
        // 建立物件
        MyClass obj = new MyClass();
        
        // 返回物件的引用
        return obj;
    }
}

// 定義一個簡單的類
class MyClass {
    public void method() {
        System.out.println("This is a method of MyClass");
    }
}

在上面的示例中,getObject() 方法返回了 MyClass 類的一個例項物件的引用。然後,該引用被賦值給 obj 變數,在 main() 方法中被使用來呼叫 method() 方法。

這種方式允許方法返回物件的引用,使得方法可以動態地建立和返回不同型別的物件,從而實現更靈活的程式設計。


main方法的引數

在 Java 中,main 方法的標準引數是 String[] args,用於接收命令列引數。這裡我會詳細介紹幾種不同的引數形式:

  1. 命令列引數:這是 main 方法的標準引數形式,用於從命令列接收引數。它是一個 String 型別的陣列,可以在程式執行時透過命令列傳遞引數給程式。

    public static void main(String[] args) {
        // your code
    }
    
  2. 不帶引數的 main 方法:雖然不常見,但是在 Java 中你也可以定義一個不帶引數的 main 方法。這種情況下,程式不會接收命令列引數。

    public static void main() {
        // your code
    }
    
  3. 帶可變引數的 main 方法:在 Java 5 中引入了可變引數,你也可以使用可變引數的形式定義 main 方法。但這種形式不是標準的 main 方法簽名。

    public static void main(String... args) {
        // your code
    }
    
  4. 使用引數名稱而不是 args:雖然 args 是約定俗成的引數名稱,但實際上你可以使用任何合法的引數名稱。只要遵循了方法的命名規範即可。

    public static void main(String[] arguments) {
        // your code
    }
    

總的來說,標準的 main 方法是第一種形式,即 public static void main(String[] args),但其他形式在特定情況下也是合法的。在實際開發中,通常還是遵循約定俗成的形式為佳,這樣可以增強程式碼的可讀性和可維護性。


main 方法裡為什麼要接受命令列引數?

main 方法接受命令列引數的主要原因是為了增加程式的靈活性和可配置性。透過命令列引數,使用者可以在執行程式時動態地傳遞一些配置資訊或引數給程式,從而影響程式的行為。

以下是一些常見的情況,可以使用命令列引數:

  1. 配置資訊:使用者可以透過命令列引數來配置程式的行為,例如指定輸入檔案的路徑、輸出檔案的路徑、日誌級別等。

  2. 執行模式:使用者可以透過命令列引數來指定程式的執行模式,例如除錯模式、測試模式、生產模式等。

  3. 傳遞資料:使用者可以透過命令列引數來傳遞資料給程式,例如需要處理的檔名、資料庫連線資訊等。

  4. 自定義功能:使用者可以透過命令列引數來啟用或禁用程式的某些功能,或者調整功能的引數。

透過接受命令列引數,程式可以更靈活地適應不同的使用場景和需求。這種靈活性使得程式更易於使用和維護,同時也提高了程式的可配置性和可擴充套件性。


main方法沒有命令列引數就不能配置和執行嗎?

不完全是這樣。雖然命令列引數提供了一種靈活的方式來配置和執行程式,但並不是所有的程式都需要使用命令列引數。即使沒有命令列引數,程式也可以進行配置和執行,只是配置的方式可能會有所不同。

以下是一些即使沒有命令列引數也可以配置和執行的方式:

  1. 配置檔案:程式可以讀取配置檔案來獲取配置資訊。配置檔案通常是以文字形式儲存的,可以包含各種配置項和引數。程式啟動時可以讀取配置檔案,並根據配置檔案中的內容進行配置和執行。

  2. 預設值:程式可以在程式碼中預先定義一些預設值作為配置的預設引數。如果沒有提供命令列引數或配置檔案,程式會使用這些預設值來進行配置和執行。

  3. 互動式輸入:程式可以與使用者進行互動,透過命令列或圖形介面等方式來詢問使用者需要的配置資訊。使用者可以根據提示輸入配置資訊,然後程式根據輸入的資訊進行配置和執行。

雖然命令列引數是一種方便的配置方式,但並不是唯一的方式。根據程式的需求和設計,可以選擇合適的配置方式來實現程式的配置和執行。


不同方式完成任務

當然,下面我會給你展示幾種不同的方式來編寫這段程式碼,雖然它們實現同樣的功能,但採用了不同的方法和技巧:

方式一:使用字元陣列

import java.util.Scanner;

public class LowerCase {
//Java程式的入口點,這個方法的簽名在Java中是固定的
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        //
        char[] input = reader.nextLine().toCharArray();
        input[0] = Character.toLowerCase(input[0]);
        System.out.print(input);
        reader.close();
    }
}

句句剖析


import java.util.Scanner;
import java.util.Scanner;

這行程式碼是 Java 中的匯入語句。它的作用是告訴編譯器在編譯過程中需要使用 java.util.Scanner 這個類。

具體含義如下:

  • import:關鍵字,用於告訴編譯器要匯入一個類或包。
  • java.util.Scanner:是一個類的完整路徑名。java.util 是 Java 標準庫中的一個包,而 Scanner 是該包中的一個類,用於從輸入流中獲取使用者的輸入。

匯入這個類後,你就可以在程式碼中使用 Scanner 類了,而不需要每次都寫完整的路徑,比如 java.util.Scanner scanner = new java.util.Scanner(System.in); 可以簡化為 Scanner scanner = new Scanner(System.in);


public static void main(String[] args){}

public static void main(String[] args) 是 Java 程式的入口點。這個方法的簽名在 Java 中是固定的,它的含義如下:

  • public:表示該方法是公共的,可以被其他類訪問。
  • static:表示該方法是靜態的,可以直接透過類名呼叫,而不需要例項化物件。
  • void:表示該方法沒有返回值。
  • main:是方法的名稱,固定為 "main"。
  • String[] args:是方法的引數,是一個字串陣列,用於傳遞命令列引數。

在一個 Java 程式中,當程式執行時,Java 虛擬機器(JVM)會首先呼叫 main 方法作為程式的入口點,開始執行程式的程式碼邏輯。因此,main 方法是 Java 程式的起點。
深度解析
當我們編寫一個 Java 程式時,我們需要指定程式的入口點,即程式從哪裡開始執行。在 Java 中,程式的入口點就是一個名為 main 的方法。

讓我們來詳細解釋一下 public static void main(String[] args) 這句話的含義:

  • public:這是一個訪問修飾符,表示該方法是公共的,可以被其他類訪問。
  • static:這是一個關鍵字,表示該方法是靜態的,即它屬於類而不是屬於物件。因此,可以透過類名直接呼叫這個方法,而不需要建立類的例項。
  • void:這是方法的返回型別。void 表示這個方法沒有返回值,即它不會返回任何資料。
  • main:這是方法的名稱,即 main 方法。
  • (String[] args):這是方法的引數列表。在這裡,(String[] args) 表示這個方法接受一個字串陣列作為引數,這個引數通常用於傳遞命令列引數。

因此,整個語句 public static void main(String[] args) 表示定義了一個名為 main 的方法,它是程式的入口點,並且接受一個字串陣列作為引數。當你執行一個 Java 程式時,JVM 會首先尋找並執行 main 方法中的程式碼,從而啟動程式的執行。


Scanner reader = new Scanner(System.in);

這句話建立了一個名為 readerScanner 物件,用於從標準輸入(通常是鍵盤)讀取使用者輸入的資料。

讓我逐步解釋:

  • Scanner:這是 Java 中的一個類,位於 java.util 包中。Scanner 類用於從各種輸入源(如檔案、字串、輸入流等)讀取資料,並將其解析為各種資料型別。

  • reader:這是建立的 Scanner 物件的名稱。在這個例子中,我們給這個物件取名為 reader,但你也可以使用其他合適的名稱。

  • = new Scanner(System.in):這部分程式碼建立了一個新的 Scanner 物件,並將其分配給 reader 變數。System.in 表示標準輸入流,通常是使用者在控制檯(命令列介面)中輸入的內容。因此,new Scanner(System.in) 表示建立一個 Scanner 物件,它會讀取使用者在控制檯中輸入的資料。

綜合起來,Scanner reader = new Scanner(System.in); 這句話的意思是建立了一個名為 readerScanner 物件,該物件用於從控制檯讀取使用者輸入的資料。


char[] input = reader.nextLine().toCharArray();

讓我一步步解釋這行程式碼:

  1. reader.nextLine():呼叫 Scanner 物件 readernextLine() 方法。這個方法用於讀取控制檯輸入的一行文字,並將其作為一個字串返回。

  2. .toCharArray()String 類的一個方法,用於將字串轉換為字元陣列。在這裡,我們使用它將 nextLine() 方法返回的字串轉換為字元陣列。

  3. char[] input = ...;:這一部分是宣告和初始化一個名為 input 的字元陣列。字元陣列是一種用於儲存字元序列的資料結構。

綜合起來,char[] input = reader.nextLine().toCharArray(); 這行程式碼的意思是從控制檯讀取使用者輸入的一行文字,並將其轉換為字元陣列儲存在名為 input 的變數中。


小知識

nextLine() 是什麼

nextLine() 是 Java 中 Scanner 類的一個方法,用於從標準輸入(通常是鍵盤)讀取一行輸入並將其作為字串返回。

具體來說,nextLine() 方法會掃描輸入中的下一行,直到遇到換行符為止(包括換行符),然後返回該行的內容,但不包括換行符本身。

在我們的程式碼中,scanner.nextLine() 用於獲取使用者輸入的整行字元,然後我們透過其他方法來處理這個輸入。

nextLine().toCharArray()是什麼?

nextLine()Scanner 類中的方法,用於從標準輸入讀取一行文字,並返回一個字串表示該行文字。

toCharArray() 是字串類 String 的方法,用於將字串轉換為字元陣列。

因此,nextLine().toCharArray() 這個表示式的意思是:

  1. 首先,從標準輸入讀取一行文字。
  2. 然後,將這行文字轉換為字元陣列。

換句話說,nextLine().toCharArray() 返回的是表示使用者輸入的整行文字的字元陣列。


字串轉化為字元陣列,儲存方式是變了嗎?原來輸入的字串的儲存空間是釋放了嗎?

當你呼叫 toCharArray() 方法將字串轉換為字元陣列時,實際上建立了一個新的字元陣列,其中包含了字串中的所有字元。這個字元陣列是新分配的記憶體空間,與原始的字串物件不同。

原始輸入的字串物件並沒有被釋放,它仍然存在於記憶體中。只是透過 toCharArray() 方法得到了一個新的字元陣列物件,它們之間沒有直接的關係。

換句話說,原始字串物件和新建立的字元陣列物件是兩個不同的物件,它們分別佔用不同的記憶體空間。原始字串物件在記憶體中仍然存在,只是不再被新的引用指向。因此,如果沒有其他引用指向原始字串物件,它將被 Java 的垃圾回收機制釋放掉,釋放其佔用的記憶體空間

更深入的解釋

理解 Java 中的記憶體分配涉及到堆記憶體和棧記憶體的概念。讓我詳細解釋一下:

  1. 棧記憶體(Stack Memory)

    • 棧記憶體用於儲存方法呼叫的區域性變數、方法引數和方法呼叫的執行上下文。
    • 當一個方法被呼叫時,會在棧記憶體中分配一塊記憶體空間,稱為棧幀(Stack Frame),用於儲存方法的區域性變數和方法引數。
    • 當方法執行完成時,棧幀被彈出,釋放其佔用的棧記憶體空間
  2. 堆記憶體(Heap Memory)

    • 堆記憶體用於儲存物件例項和陣列動態分配的資料
    • 當使用 new 關鍵字建立物件時,物件被分配在堆記憶體中
    • 物件在堆記憶體中儲存的是其成員變數的值,以及指向方法區中方法的引用等資訊。

下面是建立字串物件並轉換為字元陣列時的記憶體分配步驟:

  1. 建立字串物件

    • 當你輸入字串時,在堆記憶體中會建立一個字串物件,用於儲存這個字串的值。
    • 字串物件包含了字元序列的內容以及一些其他的資訊,例如字串的長度等。
  2. 呼叫 toCharArray() 方法

    • 當呼叫 toCharArray() 方法時,會建立一個新的字元陣列物件。
    • 這個字元陣列物件在堆記憶體中分配了一塊新的記憶體空間,用於儲存字串中的字元
  3. 複製字元資料

    • toCharArray() 方法會將字串中的字元複製到新建立的字元陣列中。
    • 這個過程涉及到將字串的字元逐個複製到字元陣列中的不同位置。
  4. 原始字串物件的釋放(如果適用):

    • 如果沒有其他引用指向原始的字串物件,它將被 Java 的垃圾回收機制自動釋放掉。
    • 原始的字串物件所佔用的堆記憶體空間將被釋放,以便其他物件可以使用。

綜上所述,建立字串物件並轉換為字元陣列時,會涉及到堆記憶體中的物件建立、複製資料以及釋放空間等步驟。


方式二:使用字串操作

import java.util.Scanner;

public class LowerCase {
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        String input = reader.nextLine();
        String output = Character.toLowerCase(input.charAt(0)) + input.substring(1);
        System.out.print(output);
        reader.close();
    }
}

方式三:使用 StringBuilder

import java.util.Scanner;

public class LowerCase {
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        StringBuilder input = new StringBuilder(reader.nextLine());
        input.setCharAt(0, Character.toLowerCase(input.charAt(0)));
        System.out.print(input);
        reader.close();
    }
}

方式四:使用字元流

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class LowerCase {
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        char firstChar = (char) reader.read();
        firstChar = Character.toLowerCase(firstChar);
        System.out.print(firstChar);
        reader.close();
    }
}

方式五:使用字元包裝類

import java.util.Scanner;

public class LowerCase {
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);
        Character firstChar = reader.nextLine().charAt(0);
        firstChar = Character.toLowerCase(firstChar);
        System.out.print(firstChar);
        reader.close();
    }
}

這些方式都能達到同樣的目的,但採用了不同的技術和方法。選擇合適的方式取決於你對不同功能的熟悉程度以及個人喜好。

不同方式的全註釋文件

當然,讓我們逐個解釋每種方式,並新增詳細的註釋:

方式一:使用字元陣列

import java.util.Scanner;

public class LowerCase {
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);

        // 從鍵盤讀取輸入,並轉換為字元陣列
        char[] input = reader.nextLine().toCharArray();

        // 將陣列中第一個字元轉換為小寫
        input[0] = Character.toLowerCase(input[0]);

        // 輸出字元陣列
        System.out.print(input);

        reader.close();
    }
}

方式二:使用字串操作

import java.util.Scanner;

public class LowerCase {
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);

        // 從鍵盤讀取輸入
        String input = reader.nextLine();

        // 將字串第一個字元轉換為小寫,然後拼接原字串後面的部分
        String output = Character.toLowerCase(input.charAt(0)) + input.substring(1);

        // 輸出結果
        System.out.print(output);

        reader.close();
    }
}

方式三:使用 StringBuilder

import java.util.Scanner;

public class LowerCase {
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);

        // 從鍵盤讀取輸入,並將其轉換為 StringBuilder 物件
        StringBuilder input = new StringBuilder(reader.nextLine());

        // 將 StringBuilder 物件的第一個字元轉換為小寫
        input.setCharAt(0, Character.toLowerCase(input.charAt(0)));

        // 輸出結果
        System.out.print(input);

        reader.close();
    }
}

方式四:使用字元流

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class LowerCase {
    public static void main(String[] args) throws IOException {
        // 建立 BufferedReader 物件用於從標準輸入讀取字元
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        // 讀取輸入的第一個字元
        char firstChar = (char) reader.read();

        // 將第一個字元轉換為小寫
        firstChar = Character.toLowerCase(firstChar);

        // 輸出結果
        System.out.print(firstChar);

        // 關閉 BufferedReader 物件
        reader.close();
    }
}

方式五:使用字元包裝類

import java.util.Scanner;

public class LowerCase {
    public static void main(String[] args) {
        Scanner reader = new Scanner(System.in);

        // 從鍵盤讀取輸入,並取第一個字元
        Character firstChar = reader.nextLine().charAt(0);

        // 將第一個字元轉換為小寫
        firstChar = Character.toLowerCase(firstChar);

        // 輸出結果
        System.out.print(firstChar);

        reader.close();
    }
}

以上是對每種方式的解釋以及帶有詳細註釋的程式碼。每種方式都使用了不同的技術和方法,你可以根據自己的喜好和專案的需求來選擇最適合的方式。

不同方式所運用到的技術

讓我更詳細地解釋每種方式所涉及的知識:

方式一:使用字元陣列

  1. Scanner 類:用於從標準輸入讀取使用者的輸入。
  2. toCharArray() 方法:將字串轉換為字元陣列,方便對單個字元進行操作。
  3. Character 類:提供了許多用於字元操作的靜態方法,如 toLowerCase() 方法用於將字元轉換為小寫形式。

方式二:使用字串操作

  1. Scanner 類:同樣用於從標準輸入讀取使用者的輸入。
  2. charAt() 方法:用於獲取字串中指定位置的字元。
  3. Character 類:同樣用於將字元轉換為小寫形式。

方式三:使用 StringBuilder

  1. Scanner 類:用於從標準輸入讀取使用者的輸入。
  2. StringBuilder 類:用於處理可變的字串序列,提供了 setCharAt() 方法來修改指定位置的字元。

方式四:使用字元流

  1. BufferedReader 類:用於從輸入流中讀取文字資料,比起 Scanner 類更高效。
  2. InputStreamReader 類:用於將位元組流轉換為字元流。
  3. IOException 異常:因為讀取輸入流可能會出現 I/O 錯誤,因此需要處理可能丟擲的 IOException 異常。
  4. 字元型別轉換:透過強制型別轉換將 int 型別的字元轉換為 char 型別。

方式五:使用字元包裝類

  1. Scanner 類:同樣用於從標準輸入讀取使用者的輸入。
  2. Character 類:用於將字元轉換為小寫形式。

以上方式涉及到了輸入輸出、字元操作、異常處理等多種知識點。選擇合適的方式取決於你對這些知識點的熟悉程度以及專案的需求。

相關文章