Java 語言提供了豐富的修飾符,主要分為兩大類:存取修飾符與非存取修飾符。修飾符用於定義類、方法或變數的特性,通常放置在語句的最前端。以下範例展示了常見的修飾符用法:
public class ClassName {
// 類體
}
private boolean myFlag;
static final double WEEKS = 9.5;
protected static final int BOX_WIDTH = 42;
public static void main(String[] arguments) {
// 方法體
}
Java 透過存取控制修飾符來保護類、變數、方法和建構子的存取權限,支援四種不同的存取等級:
使用預設修飾符聲明的變數和方法,對同一包內的類可見。介面中的變數隱式為 public static final,方法預設為 public。
String version = "1.5.1";
boolean processOrder() {
return true;
}
private 是最嚴格的存取層級。被其修飾的方法、變數和建構子只能被所屬類存取;類和介面不能聲明為 private。私有變數通常透過公有的 getter/setter 方法對外暴露,以隱藏實現細節並保護資料。
public class Logger {
private String format;
public String getFormat() { return this.format; }
public void setFormat(String format) { this.format = format; }
}
範例中,format 為私有變數,外部類無法直接存取,必須透過 getFormat() 和 setFormat() 操作。
被聲明為 public 的類、方法、建構子和介面可被任何其他類存取。若多個相互存取的公有類分布在不同包中,需導入相應包。因繼承關係,父類的公有方法和變數可被子類繼承。
public static void main(String[] arguments) { ... }
Java 程式的 main() 方法必須設為公有,否則 JVM 無法執行該類。
protected 修飾的變數、方法和建構子,可被同一包內的任何類存取,也可被不同包中的子類存取。protected 不能修飾類和介面,介面的成員也不能聲明為 protected。此修飾符常用於允許子類存取父類特定成員,同時隱藏於無關類別。
class AudioPlayer {
protected boolean openSpeaker(Speaker sp) { ... }
}
class StreamingAudioPlayer extends AudioPlayer {
boolean openSpeaker(Speaker sp) { ... } // 子類可存取並重寫
}
若聲明為 private,僅父類可存取;若為 public,所有類皆可存取;唯有 protected 能限制僅子類可見。
public 的方法,在子類中也必須為 public。protected 的方法,在子類中只能聲明為 protected 或 public,不能為 private。private 的方法,無法被繼承。為實現其他功能,Java 提供了多種非存取修飾符:
static 關鍵字聲明的變數獨立於物件,無論類實例化多少物件,靜態變數只有一份拷貝,亦稱類變數。區域變數不能聲明為 static。
static 修飾的方法獨立於物件,不能使用類的非靜態變數,僅能從參數列表獲取資料並計算。
存取方式:ClassName.variableName 或 ClassName.methodName。
public class InstanceCounter {
private static int numInstances = 0;
protected static int getCount() { return numInstances; }
private static void addInstance() { numInstances++; }
InstanceCounter() { InstanceCounter.addInstance(); }
public static void main(String[] arguments) {
System.out.println("Starting with " + InstanceCounter.getCount() + " instances");
for (int i = 0; i < 500; ++i) { new InstanceCounter(); }
System.out.println("Created " + InstanceCounter.getCount() + " instances");
}
}
執行結果:
Started with 0 instances Created 500 instances
final 變數必須顯式初始化且僅能初始化一次。被聲明為 final 的物件引用不能指向不同物件,但物件內部資料可改變。常與 static 搭配建立類常數。
public class Test {
final int value = 10;
public static final int BOX_WIDTH = 6;
static final String TITLE = "Manager";
public void changeValue() { value = 12; // 編譯錯誤 }
}
類中的 final 方法可被子類繼承,但不能被重寫。主要目的是防止方法內容被修改。
public class Test {
public final void changeName() { ... }
}
Final 類不能被繼承,無類能繼承其任何特性。
public final class Test { ... }
抽象類不能實例化物件,旨在供未來擴充。類不能同時被 abstract 和 final 修飾。若類包含抽象方法,必須聲明為抽象類。抽象類可包含抽象與非抽象方法。
abstract class Caravan {
private double price;
private String model;
private String year;
public abstract void goFast();
public abstract void changeColor();
}
抽象方法無實現,具體實現由子類提供。不能聲明為 final 或 strict。繼承抽象類的子類必須實現所有抽象方法,除非子類也是抽象類。抽象方法宣告以分號結尾,如 public abstract void sample();。
public abstract class SuperClass {
abstract void m();
}
class SubClass extends SuperClass {
void m() { ... }
}
synchronized 關鍵字聲明的方法同一時間只能被一個執行緒存取,可應用於四種存取修飾符。
public synchronized void showDetails() { ... }
序列化物件包含 transient 修飾的實例變數時,JVM 會跳過該變數。用於預處理類和變數的資料類型。
public transient int limit = 55; // 不持久化 public int b; // 持久化
volatile 修飾的成員變數在每次被執行緒存取時,強制從共享記憶體重讀值;變數發生變化時,強制將變化寫回共享記憶體,確保所有執行緒看到一致的值。volatile 物件引用可能為 null。
public class MyRunnable implements Runnable {
private volatile boolean active;
public void run() {
active = true;
while (active) { ... }
}
public void stop() { active = false; }
}
若無 volatile,執行緒可能使用緩衝區舊值導致迴圈不停止。