Java 靜態字段與靜態方法(學習 Java 編程語言 031)

1. 靜態字段

靜態字段就是將字段定義爲 static 的字段,類的全部實例共享一個靜態字段。靜態字段屬於類,而不屬於任何單個對象。而對於非靜態的實例字段,每一個對象都有本身的一個副本。java

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

如今,每一個 Employee 對象都一個本身的 id 字段,但 Employee 類的全部實例將共享一個 nextId 字段。即便沒有 Employee 對象,靜態字段 nextId 也存在。它屬於類,而不屬於任何單個對象。ide

2. 靜態常量

靜態變量使用得比較少,但靜態常量卻很經常使用。例如,在 Math 類中定義了一個靜態常量。單元測試

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

在程序中,能夠用 Math.PI 來訪問這個常量。測試

若是省略關鍵字 static,PI 就變成了 Math 類的一個實例字段。也就是說,須要經過 Math 類的一個對象來訪問 PI,而且每個 Math 對象都有它本身的一個 PI 副本。ui

另外一個靜態常量是 System.out。在 System 類中聲明以下:this

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

因爲每一個類對象均可以修改公共字段,因此,最好不要有公共字段。然而,公共常量(即 final 字段)卻沒有問題。所以 out 被聲明爲 final,因此,不容許再將它從新賦值爲另外一個打印流:
System.out = new PrintStream(...); // 錯誤,out 是 final 常量code

註釋: 若是查看 System 類,就會發現有一個 setOut 方法能夠將 System.out 設置爲不一樣的流。你可能會感到奇怪,爲何這個方法能夠修改 final 變量的值。緣由在於,setOut 方法是一個原生方法,而不是在 Java 語言中實現的。原生方法能夠繞過 Java 語言的訪問控制機制。這是一種特殊的解決方案,在本身編寫程序時不要模仿這種作法。orm

3. 靜態方法

靜態方法是不在對象上執行的方法。例如,Math 類的 pow 方法就是一個靜態方法。表達式:
Math.pow(x, a)
會計算冪 x<sup>a</sup>。在完成計算時,它並不使用任何 Math 對象。換句話說,它沒有隱式參數。對象

能夠認爲靜態方法是沒有 this 參數的方法(在一個非靜態的方法中,this 參數指示這個方法的隱式參數)。ci

靜態方法不能訪問實例字段,由於靜態方法不能在對象上執行操做。可是,靜態方法能夠訪問靜態字段。

class Employee
{
    private static int nextId = 1;
    private int id;
    public static int getNextId(){
        return nextId; // 返回靜態字段
    }
    ...
}

能夠提供類名來調用這個方法:
int n = Employee.getNextId();

註釋:可使用對象調用靜態方法,這是合法的。例如,若是 harry 是一個 Employee 對象,可使用 harry.getNextId() 替代 Employee.getNextId()。不過,這種方式很容易形成混淆,其緣由是 getNextId 方法計算的結果與 harry 毫無關係。咱們建議使用類名而不是對象來調用靜態方法。

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

  • 方法不須要訪問對象狀態,由於它須要的全部參數都經過顯示參數提供(例如,Math.pow)。
  • 方法只須要訪問類的靜態字段(例如:Employee.getNextId())。

4. 工廠方法

靜態方法還有另一種常見的用途。相似 LocalDate 和 NumberFormat 的類使用靜態工廠方法(factory method)來構造對象。例如工廠方法 LocalDate.now 和 LocalDate.of。NumberFormat 類以下生成不一樣風格的格式化對象。

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

NumberFormat 類不利用構造器完成這些操做的兩個主要緣由:

  • 沒法命名構造器,構造器的名字必須與類名相同。可是,這裏但願有兩個不一樣的名字,分別獲得貨幣實例和百分比實例。
  • 使用構造器時,沒法改變所構造對象的類型。而工廠方法實際上將返回 DecimalFormat 類的對象,這是 NumberFormat 的子類。

5. main 方法

能夠調用靜態方法而不須要任何對象。例如,不須要構造 Math 類的任何對象,就能夠調用 Math.pow。

main 方法是一個靜態方法。

public class Application {
    public static void main(String[] args) {
        // 在這裏構造對象
    }
}

main 方法不對任何對象進行操做。事實上,在啓動程序時尚未任何一個對象。靜態 main 方法將執行並構造程序所須要的對象。

每個類能夠有一個 main 方法。這是經常使用於對類進行單元測試的一個技巧。

6. 其餘 API

java.util.Objects 7

  • static &lt;T&gt; void requireNonNull(T obj)

    若是 obj 爲 null,會拋出一個 NullPointerException 異常而沒有拋出消息。

  • static &lt;T&gt; void requireNonNull(T obj, Strimg message)

    若是 obj 爲 null,會拋出一個 NullPointerException 異常而拋出給定消息。

  • static &lt;T&gt; void requireNonNull(T obj, Supplier&lt;Strimg&gt; messageSupplier)

    若是 obj 爲 null,會拋出一個 NullPointerException 異常而拋出給定消息。

  • static &lt;T&gt; T requireNonNullElse(T obj, T defaultObj)

    若是 obj 不爲 null 則返回 obj,或者若是 obj 爲 null 則返回默認對象。

  • static &lt;T&gt; T requireNonNullElseGet(T obj, Supplier&lt;T&gt; defaultSupplier)

    若是 obj 不爲 null 則返回 obj,或者若是 obj 爲 null 則返回默認對象。

相關文章
相關標籤/搜索