Java訪問修飾符:public、private、protected,控制可見性

在Java中,我們寫的代碼是由一個個類和類的成員(方法、變量等)組成的。爲了讓代碼更安全、更易於維護,Java提供了訪問修飾符來控制這些成員的可見範圍——也就是哪些地方可以訪問它們,哪些地方不能。這篇文章我們就來聊聊最常用的三個訪問修飾符:publicprivateprotected,看看它們是如何控制可見性的。

爲什麼需要訪問修飾符?

想象一下,如果所有類的成員都能被任何地方直接訪問,那麼代碼可能會被隨意修改或誤操作。比如,一個銀行賬戶的餘額如果可以被任何人直接修改,那會有多危險?訪問修飾符就像“門禁”,幫我們控制誰能進、誰不能進。

1. public:公開的,所有地方都能訪問

public 是最“開放”的修飾符,表示成員對所有類都是可見的,無論在同一個包還是不同包中。

例子
假設我們有一個類 Person,裏面有一個 public 方法,其他類無論在哪裏都能調用它。

// 類 Person 在包 com.example 下
package com.example;

public class Person {
    // public 方法,所有地方都能調用
    public void sayHello() {
        System.out.println("Hello!");
    }
}

// 另一個類 OtherClass 在不同包 com.test 下
package com.test;

import com.example.Person; // 導入 Person 類

public class OtherClass {
    public static void main(String[] args) {
        Person person = new Person();
        person.sayHello(); // 成功調用!public 方法跨包可訪問
    }
}

結論public 成員可以被任何類直接訪問,包括不同包的類。

2. private:私有的,僅限當前類內部訪問

private 是最“嚴格”的修飾符,表示成員只能在定義它的類內部訪問,其他類(包括同一包的其他類)都無法直接訪問。

例子
假設 Person 類有一個 private 變量,其他類(即使在同一個包)也無法直接讀取或修改它。

// 類 Person 在包 com.example 下
package com.example;

class Person {
    private String name; // 私有變量,只能 Person 自己訪問

    private void printName() { // 私有方法,只能 Person 自己調用
        System.out.println("Name: " + name);
    }

    // 提供 public 方法讓外部間接訪問私有變量
    public void setName(String n) {
        name = n;
    }

    public void getName() {
        printName(); // 內部調用私有方法
    }
}

// 同一包中的類 OtherClass,嘗試訪問 Person 的 private 成員
package com.example;

public class OtherClass {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("Alice"); // 正確:通過 public 方法設置
        person.getName(); // 正確:通過 public 方法獲取

        // 錯誤!private 成員不能直接訪問
        // System.out.println(person.name); // 編譯報錯:無法訪問私有成員
        // person.printName(); // 編譯報錯:無法訪問私有方法
    }
}

結論private 成員只能在類內部訪問,外部類必須通過類提供的 public 方法(如 getter/setter)間接訪問。

3. protected:受保護的,同包可訪問,子類可訪問

protected 修飾符的可見性介於 publicprivate 之間,需要區分兩種情況:
- 同包內:和 public 類似,同一個包中的類可以直接訪問 protected 成員。
- 不同包的子類:如果一個類繼承了定義 protected 成員的父類,那麼子類可以通過繼承的方式訪問這些成員(即使子類和父類不在同一個包)。

例子1:同包內訪問

// 類 A 和類 B 在同一個包 com.example 下
package com.example;

class A {
    protected int age = 20; // 受保護的變量,同包可訪問
}

class B {
    public static void main(String[] args) {
        A a = new A();
        System.out.println(a.age); // 正確:同包可直接訪問
    }
}

例子2:不同包的子類訪問

// 父類 Person 在包 com.example 下
package com.example;

public class Person {
    protected String name; // 受保護的變量

    protected void showName() {
        System.out.println("Name: " + name);
    }
}

// 子類 Student 在不同包 com.test 下,繼承自 Person
package com.test;

import com.example.Person; // 導入父類

public class Student extends Person {
    public void displayInfo() {
        name = "Bob"; // 子類可直接訪問父類的 protected 變量
        showName();   // 子類可直接調用父類的 protected 方法
    }
}

// 測試類,嘗試訪問非子類的 protected 成員
package com.test;

import com.example.Person;

public class Test {
    public static void main(String[] args) {
        Person person = new Person();
        // 錯誤!Test 不是 Person 的子類,不同包無法訪問 protected 成員
        // System.out.println(person.name); // 編譯報錯
    }
}

結論protected 成員在同包內不同包的子類中可以訪問,但非子類的不同包類無法訪問。

4. 默認修飾符(無修飾符):同包可訪問

如果一個成員沒有任何修飾符(即“默認”修飾符),它的可見範圍是僅在同一個包內可訪問,不同包的類無法訪問。

例子

// 類 A 和類 B 在同一個包 com.example 下
package com.example;

class A {
    int count = 10; // 默認修飾符,同包可訪問
}

class B {
    public static void main(String[] args) {
        A a = new A();
        System.out.println(a.count); // 正確:同包可直接訪問
    }
}

// 不同包的類嘗試訪問默認成員
package com.test;

import com.example.A;

public class Test {
    public static void main(String[] args) {
        A a = new A();
        // 錯誤!不同包無法訪問默認成員
        // System.out.println(a.count); // 編譯報錯
    }
}

結論:默認修飾符成員僅在同包內可見,不同包不可訪問。

總結:訪問修飾符對比表

修飾符 同包內類 不同包的非子類 不同包的子類 其他包類
public ✅ 是 ✅ 是 ✅ 是 ✅ 是
private ❌ 否 ❌ 否 ❌ 否 ❌ 否
protected ✅ 是 ❌ 否 ✅ 是 ❌ 否
默認 ✅ 是 ❌ 否 ❌ 否 ❌ 否

實際開發中的建議

  • 成員變量優先用 private:通過 public 方法(如 getter/setter)控制訪問,既能保證數據安全,又能在方法中添加邏輯(比如驗證數據)。
  • 控制類的可見性:如果類只在當前包內使用,用默認修飾符;如果需要被其他包的類使用,用 public
  • protected 用於繼承場景:比如父類想讓子類訪問某些成員,但又不想讓其他類訪問,就用 protected

掌握訪問修飾符,是寫出安全、清晰代碼的第一步!

小夜