本文為 Java 基礎入門 系列文,第 1 篇:
在 Java 開發中,存取權限(Access Modifiers)決定了一個類別(class)或其成員(屬性與方法)能被哪些地方存取。
這就像是房子的門鎖,你可以選擇讓所有人都能進入(public),只讓家人進來(protected),只讓自己進入(private),或是讓同一社區的人進入(預設)。
了解這些存取權限,可以幫助我們保護程式的內部結構,確保安全性與封裝性(Encapsulation)。
Java 中的 package 是什麼?
package(封裝、套件)是 Java 用來管理類別和避免名稱衝突的一種方式。
在 Java 中,每個 .java 檔案只能屬於一個 package,而且 package 的宣告必須放在 .java 檔案的第一行(import 之前)。
這表示該檔案內的所有類別都屬於同一個 package,不能同時屬於多個 package。
如何宣告 package?
每個 .java 檔案的開頭都可以加上 package 宣告,格式如下:
package mypackage; // 這個類別屬於 mypackage
public class MyClass {
public void sayHello() {
System.out.println("Hello from MyClass!");
}
}一個 .java 檔案只能有一個 package
mypackage/MyClass.java
package mypackage; // 指定這個檔案屬於 mypackage
public class MyClass {
public void sayHello() {
System.out.println("Hello from MyClass!");
}
}
這個檔案屬於 mypackage,所以它裡面的所有類別都在 mypackage 這個範圍內。
錯誤示範:一個 .java 檔案不能有多個 package
package package1;
package package2; // ❌ 錯誤!一個檔案只能有一個 package
public class Test {
public static void main(String[] args) {
System.out.println("Hello!");
}
}
🔴 錯誤訊息:
Only a single package declaration is allowedJava 不允許一個 .java 檔案同時屬於 package1 和 package2。
package 的目錄結構
package(封裝、套件)是 Java 用來管理類別和避免名稱衝突的一種方式。
你可以把它想像成資料夾系統,每個 package 就像是一個資料夾,裡面可以存放相關的 Java 類別。
例如,以下 package 結構:
graph TD;
A[src] --> B[mypackage]
A[src] --> C[anotherpackage]
%% mypackage 內容
B --> B1[MyClass.java]
B --> B2[Helper.java]
B --> B3[DataModel.java]
%% anotherpackage 內容
C --> C1[Test.java]
C --> C2[Utils.java]
C --> C3[Config.java]mypackage內的MyClass.java屬於mypackageanotherpackage內的Test.java屬於anotherpackage
多個 .java 檔案可以屬於同一個 package
雖然 一個 .java 檔案只能有一個 package,但多個 .java 檔案可以屬於同一個 package。這在大型專案中很常見。
例如:
src/
└── mypackage/
├── Aaa.java
├── Bbb.java
Aaa.java
package mypackage;
public class Aaa {
public void sayHello() {
System.out.println("Hello from Aaa!");
}
}
Bbb.java
package mypackage;
public class Bbb {
public void sayHi() {
System.out.println("Hi from Bbb!");
}
}
Test.java
package mypackage; // 同一個 package,Aaa 和 Bbb 都可存取
public class Test {
public static void main(String[] args) {
Aaa obj1 = new Aaa();
obj1.sayHello();
Bbb obj2 = new Bbb();
obj2.sayHi();
}
}
✅ Aaa 和 Bbb 都屬於 mypackage,所以它們可以直接互相存取,不需要 import。
Java 內建的 package
Java 內建很多標準 package,例如:
java.util:提供工具類,例如ArrayList、HashMapjava.io:處理輸入輸出,例如File、BufferedReaderjava.net:處理網路請求,例如URL、Socket
你可以直接 import 這些標準類別來使用:
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("Hello");
System.out.println(list);
}
}
如何在不同 package 引用類別?
範例:兩個不同 package 的類別
mypackage/MyClass.java(定義類別)
package mypackage; // 類別屬於 mypackage
public class MyClass {
public void sayHello() {
System.out.println("Hello from MyClass!");
}
}
anotherpackage/Test.java(引用 mypackage 內的 MyClass)
package anotherpackage;
import mypackage.MyClass; // 必須 import 來引用其他 package 內的類別
public class Test {
public static void main(String[] args) {
MyClass obj = new MyClass(); // ✅ OK
obj.sayHello();
}
}
⚠️ 注意!如果沒有
import mypackage.MyClass;,Test.java會找不到MyClass,因為它們不在同一個package。
Java 類別的四種存取權限
Java 中的類別存取權限有四種:
| 存取修飾詞 | 可用在頂層類別? | 存取範圍 |
|---|---|---|
public | ✅ 可以 | 任何地方(跨 package 也可存取) |
| 預設(package-private) | ✅ 可以 | 只能在相同的 package 內存取 |
private | ❌ 不能 | 只能用在內部類別,外部無法存取 |
protected | ❌ 不能 | 只能在相同的 package 或子類別內存取 |
注意: 頂層類別(定義在
.java檔案內的主要類別)只能是public或預設(package-private),不能是private或protected。
public(公開)
特性
- ✅ 可以被任何地方存取(不同 package 也可以)。
- ✅ 必須與
.java檔案名稱相同。
範例
MyClass.java(定義一個 public 類別)
public class MyClass {
void sayHello() {
System.out.println("Hello!");
}
}
Test.java(存取 public 類別,來自不同的檔案或 package)
public class Test {
public static void main(String[] args) {
MyClass obj = new MyClass(); // OK,public 類別可存取
obj.sayHello();
}
}
✅ MyClass 可以在任何地方使用,不管是不是同一個 package。
預設(package-private)
特性
- ✅ 只能在相同 package 內存取。
- ✅ 不需要與
.java檔案名稱相同。
範例
MyClass.java(沒有 public,預設為 package-private)
class MyClass { // 預設存取權限(package-private)
void sayHello() {
System.out.println("Hello!");
}
}
Test.java(與 MyClass.java 在同一個 package)
public class Test {
public static void main(String[] args) {
MyClass obj = new MyClass(); // OK,因為在同一個 package
obj.sayHello();
}
}
✅ MyClass 可以在同一個 package 內存取,但不同 package 無法存取。
🚫 錯誤示範:不同 package 嘗試存取 package-private 類別
import mypackage.MyClass; // ❌ 錯誤!
public class AnotherTest {
public static void main(String[] args) {
MyClass obj = new MyClass(); // ❌ 無法存取!
}
}
🔴 錯誤訊息:
MyClass is not public in mypackage; cannot be accessed from outside packageprivate(私有)
特性
- ❌ 不能用在「頂層類別」。
- ✅ 可以用在「內部類別(Nested Class)」。
🚫 錯誤示範:private 不能用在頂層類別
private class MyClass { // ❌ 錯誤!
void sayHello() {
System.out.println("Hello!");
}
}
🔴 錯誤訊息:
modifier 'private' not allowed here✅ 正確用法:private 內部類別
public class OuterClass {
private static class InnerClass { // OK
void sayHello() {
System.out.println("我是內部類別!");
}
}
public static void main(String[] args) {
InnerClass obj = new InnerClass();
obj.sayHello();
}
}
protected(受保護)
特性
- ❌ 不能用在「頂層類別」。
- ✅ 只能在相同 package 或子類別中存取。
🚫 錯誤示範:protected 不能用在頂層類別
protected class MyClass { // ❌ 錯誤!
void sayHello() {
System.out.println("Hello!");
}
}
🔴 錯誤訊息: modifier 'protected' not allowed here
✅ 正確用法:protected 內部類別
public class OuterClass {
protected static class InnerClass { // OK
void sayHello() {
System.out.println("我是受保護的內部類別!");
}
}
}
✅ protected 方法允許子類別存取
class Animal {
protected void makeSound() {
System.out.println("動物發出聲音");
}
}
class Dog extends Animal {
void bark() {
makeSound(); // ✅ OK
System.out.println("汪汪!");
}
}
總結
package 幫助我們組織 Java 類別,而存取修飾詞決定了類別之間的可見性。透過正確使用這些概念,我們可以提升程式碼的安全性、可維護性與結構化!
這樣的存取控制讓 Java 的程式碼更易讀、更安全、更容易維護,並且符合物件導向的設計原則!