CodeGym /課程 /JAVA 25 SELF /存取修飾子與變數的作用域

存取修飾子與變數的作用域

JAVA 25 SELF
等級 8 , 課堂 5
開放

1. 介紹

Java 中,就像在生活裡,並不是所有東西都應該隨時對所有人開放。想像你的公寓:你不會希望鄰居走進你的臥室,對吧?在程式裡也是如此,有時我們想要「關上門」,讓某些變數或方法無法被外部直接存取。

為此,在 Java 中有存取修飾子——一些特殊關鍵字,用來指定某個變數或方法在哪裡可以被使用:例如 publicprivate

主要的存取修飾子

修飾子 可見範圍
public
在任何看得到該類別的地方(包含其他封包與其他檔案)
private
僅在同一個類別內
(無修飾子)
僅在同一個封包內(亦即同一資料夾中的類別)

還有其他修飾子,不過等我們談到繼承時再介紹。

實務範例

public class User 
{
    public String name;           // 對所有人可見
    private int age;              // 僅在 User 類別內可見

    public void sayHello() 
    {
        System.out.println("嗨,我叫 " + name);
    }

    private void secretMethod() 
    {
        System.out.println("這是祕密方法!");
    }
}

說明:

  • name — 在能使用 User 類別的任何地方都可見。
  • age — 僅在 User 類別內可見。
  • sayHello() — 公開方法,可從任何其他類別呼叫。
  • secretMethod() — 私有方法,無法從外部呼叫。

在實務中如何運作?
假設我們有個表示銀行帳戶的類別。我們當然不希望任何人都能直接改變餘額!因此,餘額欄位會是 private,並提供專門的方法來操作它。

為什麼不該把一切都設成 public?

你可能會有個誘惑:「那就把所有東西都設成 public,省得麻煩!」但這只會走向混亂。想像任何人都能改你的餘額、使用者名稱,甚至呼叫僅供內部使用的方法。在大型程式中,這會導致錯誤與各種「神祕」的 bug。

Java 開發者的黃金法則:
先將一切設為 private,再只對外開放真正需要的部分。

2. 變數的作用域

作用域是指變數「存在」且可被使用的那段程式區域。一旦超出該區域,變數就「消失」了——彷彿它從未存在。

Java 中,依作用域來看有幾種變數:

  • 區域變數——宣告在方法或程式區塊 { ... } 之內。
  • 方法參數——在方法的圓括號中宣告。
  • 類別欄位——宣告在類別內、方法之外。

如果變數宣告在 { 區塊 } 之內,
它只在該 區塊 內可見,
在其外部無法存取。
區域變數的作用域

區域變數

區域變數只存在於它被宣告的那個方法或區塊中。

void printSum(int a, int b) 
{
    int sum = a + b; // 區域變數
    System.out.println(sum);
}
// 這裡 sum 已經不存在了!

嘗試在方法之外存取 sum 會造成編譯錯誤:「找不到變數 sum」。

方法參數

參數也是變數,但它們只在方法內存活。

void greet(String name) 
{
    System.out.println("嗨," + name);
}
// 這裡 name 已經不存在了!

類別欄位(成員變數)

類別欄位宣告在類別中、方法之外。它們在此類別的所有方法中皆可見。

public class Counter 
{
    private int count = 0; // 類別欄位

    public void increment() 
    {
        count++; // 可以使用欄位
    }

    public int getCount() 
    {
        return count; // 也可以使用欄位
    }
}

3. 變數遮蔽 (Shadowing)

遮蔽(shadowing)是指在某個作用域內宣告了與外層作用域同名的變數(或參數)。在該區塊內,「新的」名稱會遮蔽外層的名稱,因此無法直接存取外層的值。

遮蔽範例:

class ShadowDemo 
{
    int value = 10; // 類別欄位

    void printValue() 
    {
        System.out.println(value);  // 10 — 輸出類別欄位
        int value = 5; // 區域變數遮蔽了類別欄位
        System.out.println(value); // 輸出 5,而不是 10
    }
}

在此範例中,當我們寫下 int value = 5; 時,是宣告了一個新的區域變數,它的優先序高於同名的類別欄位。於是在方法 printValue() 內存取 value 時,會使用區域變數而非類別欄位。

如果仍需要存取類別的靜態欄位,請使用類別名稱作為前綴:

class ShadowDemo 
{
    static int value = 10; // 類別的靜態欄位 

    void printValue() 
    {
        System.out.println(value);      // 10 — 類別欄位
        int value = 5;
        System.out.println(value);      // 5 — 區域變數
        System.out.println(ShadowDemo.value); // 10 — 類別的靜態欄位,透過 'ShadowDemo' 存取
    }
}

若要存取非靜態的類別欄位,請使用關鍵字 this。它指向目前物件的實例。

class ShadowDemo 
{
    int value = 10;

    void printValue() 
    {
        System.out.println(value);      // 10 — 類別欄位
        int value = 5;
        System.out.println(value);      // 5 — 區域變數
        System.out.println(this.value); // 10 — 類別欄位,透過 'this' 存取
    }
}

4. 實作練習:存取修飾子與作用域

讓我們繼續擴充教學用應用程式:一個簡單的學生管理系統。為欄位與方法設定不同的存取修飾子。

範例:Student 類別

public class Student 
{
    public String name;        // 學生姓名(對所有人可見)
    private int age;           // 年齡(僅在類別內可見)

    public Student(String name, int age) 
    {
        this.name = name;
        this.age = age;
    }

    public void sayHello() 
    {
        System.out.println("嗨,我叫 " + name);
    }

    private void printSecret() 
    {
        System.out.println("我的年齡: " + age);
    }

    public void revealSecret() 
    {
        printSecret(); // 可在類別內呼叫私有方法
    }
}

Student 類別的使用

public class Main 
{
    public static void main(String[] args) 
    {
        Student s = new Student("Vasya", 20);
        s.sayHello();       // OK:公開方法
        s.revealSecret();   // OK:公開方法,它會在類別內呼叫私有方法

        s.age = 30;      // 錯誤!欄位 age 是私有的

        s.printSecret(); // 錯誤!方法 printSecret 是私有的
    }
}

5. 使用存取修飾子與作用域時的常見錯誤

錯誤 №1:把所有東西都設為 public —— 混亂就此登場!
如果將所有欄位與方法都設為公開,你將失去對資料如何被修改的控制。請將欄位設為 private,並只對外開放必要的部分。

錯誤 №2:嘗試在變數的作用域之外使用它。
例如,在方法內宣告了變數,卻試圖在方法外存取——一定會得到編譯錯誤。區域變數只在它的 { ... } 區塊中存活。

錯誤 №3:名稱衝突(變數遮蔽)。
如果在方法中宣告了與類別欄位相同名稱的變數,很容易混淆你實際使用的是哪一個。請使用 this 來明確指向類別欄位:this.value

錯誤 №4:從其他類別存取 private 方法或欄位。
若方法或欄位標記為 private,它們只在同一個類別內可見。從外部存取會導致編譯錯誤。

錯誤 №5:忽略了迴圈或區塊的作用域。
在迴圈或任何 { } 區塊內宣告的變數,只在該區塊內存活。區塊外即不存在。

1
問卷/小測驗
方法,等級 8,課堂 5
未開放
方法
方法的宣告與呼叫
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION