【java基礎(十七)】靜態域與靜態方法

在前面的示例中,main方法都被標記爲static修飾符。我們來具體討論一下這個修飾符的含義。

靜態域

如果將域定義爲static,每個類中只有一個這樣的域。而每一個對象對於所有的實例域卻都有自己的一份拷貝。例如,假定需要給每一個僱員賦予唯一的標識碼。這裏給Employee類添加一個實例域id和一個靜態域nextId:

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

現在,每一個僱員對象都有一個自己的id域,但這個類的所有實例都將共享一個nextId域。換句話說,如果有1000個Employee類的對象,則有1000個實例域id。但是,只有一個靜態域nextId。即使沒有一個僱員對象,靜態域nextId也存在。它屬於類,而不屬於任何獨立的對象。
下面實現一個簡單的方法:

public void setId() {
	id = nextId;
	nextId++;
}

假定爲harry設定僱員標識碼:
harry.setId()
harry的id域被設置爲靜態域nextId當前的值,並且靜態域nextId的值加1:

harry.id = Employee.nextId;
Employee.nextId++;

靜態常量

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

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

在程序中,可以採用Math.PI的形式獲得這個常量。
如果關鍵字static被省略,PI就變成了Math類的一個實例域。需要通過Math類的對象訪問PI,並且每一個Math對象都有它自己的一份PI拷貝。
另一個多次使用的靜態常量是System.out。它在System類中聲明:

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

之前說過,由於每個類對象都可以對共有域進行修改,所以,最好不要將域設計爲public。然而,共有常量(即final域)卻沒問題。因爲out被聲明爲final,所以,不允許再將其他打印流賦給它:

System.out = new PrintStream(...); // 這是錯誤的,因爲out是final的,不能被修改。

靜態方法

靜態方法是一種不能向對象實施操作的方法。例如,Math類的pow方法就是一個靜態方法。表達式

Math.pow(x, a);

計算x的a次冪,不使用任何Math對象。換句話說,沒有隱式的參數。
可以認爲靜態方法是沒有this參數的方法。
Employee類的靜態方法不能訪問Id實例域,因爲它不能操作對象。但是,靜態方法可以訪問自身類的靜態域。如:

public static int getNextId() {
	return nextId;
}

可以通過類名調用這個方法:

int n = Employee.getNextId();

這個方法可以省略關鍵字static嗎?答案是肯定的。但是,需要通過Employee類對象的引用調用這個方法。
在下面兩種情況下使用靜態方法:

  • 一個方法不需要訪問對象狀態,其所需參數都是通過顯示參數提供(如:Math.pow)。
  • 一個方法只需要訪問類的靜態域(如:Employee.getNextId)。

工廠方法

靜態方法還有另外一個常見的用途。類似LocalDate和NumberFormat的類使用靜態工廠方法(factory method)來構造對象。NumberFormat類如下使用工廠方法生成不同風格的格式化對象:

NumberFormat currencyFormatter = NumberFormat.getCurrencyInstance();
NumberFormat percentFormatter = NumberFormat.getPercentInstance();
double x = 0.1;
System.out.println(currencyFormatter.format(x)); // $0.10
System.out.println(percentFormatter.format(x)); // 10%

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

  • 無法命名構造器。構造器的名字必須與類名相同。但是,這裏希望得到的貨幣實例和百分比實例採用不同的名字。
  • 當使用構造器時,無法改變所構造的對象類型。而Factory方法將返回一個DecimalFormat類對象,這是NumberFormat類的子類(後續詳細講解)。

main方法

需要注意,不需要使用對象調用靜態方法。例如,不需要構造Math類就可以調用Math.pow。
同理,main方法也是一個靜態方法。

public class Application {
	public static void main(String[] args) {
		...
	}
}

main方法不對任何對象進行操作。事實上,在啓動程序時還沒有任何一個對象。靜態的main方法將執行並創建程序所需要的對象。

單元測試

每一個類可以有一個main方法。這是一個常用語對類進行單元測試的技巧。例如,可以在Employee類總添加一個main方法:

class Employee {
	...
	public static void main(String[] args) {
		Employee e = new Employee("Romeo", 50000, 2003, 3, 31);
		e.raiseSalary(10);
		System.out.println(e.getName() + " " + e.getSalary());
	}
}

如果想要獨立地測試Employee類,只需要執行
java Employee
如果Employee類是一個更大型程序的一部分,就可以執行大型程序的入口類:
java Application
Employee類的main方法永遠不會執行。

捐贈

若你感覺讀到這篇文章對你有啓發,能引起你的思考。請不要吝嗇你的錢包,你的任何打賞或者捐贈都是對我莫大的鼓勵。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章