Java的static修飾符

真正的飛魚發表於2023-04-26

靜態域

如果將域定義為 static,每個類中只有一個這樣的域。而每一個物件對於所有的例項域卻都有自己的一份複製。例如,假定需要給每一個僱員賦予唯一的標識碼。這裡給 Employee 類新增一個例項域 id 和一個靜態域 nextld:

class Employee {
	private static int nextId = 1;
	private int id;
}

現在,每一個僱員物件都有一個自己的 id 域,但這個類的所有例項將共享一個 nextId 域。換句話說,如果有 1000 個 Employee 類的物件,則有 1000 個例項域 id。但是,只有一個靜態域 nextld。即使沒有一個僱員物件,靜態域 nextld 也存在。靜態域它屬於類,而不屬於任何獨立的物件。

靜態常量

靜態變數使用得比較少,但靜態常量卻使用得比較多。例如,在 Math 類中定義了一個靜態常量:

public class Math {
	public static final double PI = 3.14159265358979323846;
}

在程式中,可以採用 Math.PI 的形式獲得這個常量。

如果關鍵字 static 被省略,PI 就變成了 Math 類的一個例項域。需要透過 Math 類的物件訪問 PI,並且每一個 Math 物件都有一份它自己的 PI 複製。


另一個多次使用的靜態常量是 System.out。它在 System 類中宣告:

public class System {
	public static final PrintStream out = ...;
}

由於每個類物件都可以對公有域進行修改,所以,最好不要將域設計為 public。然而,公有常量(即 public static final 域)卻沒問題。 因為 out 被宣告為 final,所以不允許再將其他列印流賦值給 out。

靜態方法

靜態方法是一種不能向物件實施操作的方法。例如,Math 類的 pow() 方法就是一個靜態方法。表示式 Math.pow(x, a) 計算冪 xa。在計算時不使用任何 Math 物件。換句話說,沒有隱式的引數。

可以認為靜態方法是沒有 this 引數的方法(在一個非靜態的方法中,this 參數列示這個方法的隱式引數。)


Employee 類的靜態方法不能訪問 id 例項域,因為它不能操作物件。但是,靜態方法可以訪問自身類中的靜態域。下面是使用這種靜態方法的一一個示例:

public static int getNextId() {
	return nextId; // returns static field
}

可以透過類名呼叫這個方法:int n = Employee.getNextId();


在下面兩種情況下使用靜態方法:

  • 一個方法不需要訪問物件狀態,其所需引數都是透過顯式引數提供(例如:Math.pow())
  • 一個方法只需要訪問類的靜態域(例如:Employee.getNextId())

Java 中的靜態域與靜態方法在功能上與 C++ 相同。但是,語法書寫上卻稍有所不同。在 C++ 中,使用 :: 運算子訪問自身作用域之外的靜態域和靜態方法,如 Math::PI。

工廠方法

靜態方法還有另外一種常見的用途。類似 LocalDate 和 NumberFormat 的類使用靜態工廠方法(factory method)來構造物件。你已經見過工廠方法 LocalDate.now() 和 LocalDate.of()。

NumberFormat 類如下使用工廠方法生成不同風格的格式化物件:

NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance();
NumberFormat percentFormatter = NumberFormat.getPercentlnstance();

double x = 0.1;
System.out.println(currencyFormatter.format(x)); // prints $0.10
System.out.println(percentFomatter.format(x)); // prints 10%

為什麼 NumberFormat 類不利用構造器完成這些操作呢?這主要有兩個原因:

  • 無法命名構造器。構造器的名字必須與類名相同。但是,這裡希望將得到的貨幣例項和百分比例項採用不用的名字。
  • 當使用構造器時,無法改變所構造的物件型別。而 Factory 方法將返回一個 DecimalFormat 類物件,這是 NumberFormat 的子類。

參考資料

《Java核心技術卷一:基礎知識》(第10版)第 4 章:物件與類 4.4 靜態域與靜態方法

相關文章