關於Java static的常見問題和使用誤區

2020-07-16 10:05:17
學完《Java static關鍵字》一節我們可能會產生很多疑問,所以本節主要講解學習 Java 中關於 static 常見的幾個問題。

1)為什麼要用”static“關鍵字?

通常來說,用 new 建立類的物件時,資料儲存空間才被分配,方法才供外界呼叫。有時候我們只想為特定域分配單一儲存空間,不考慮要建立多少物件或者說根本就不建立任何物件,有時候我們想在沒有建立物件的情況下也想呼叫方法。在這兩種情況下,static 關鍵字,滿足了我們的需求。

2)”static“關鍵字是什麼意思?Java 中是否可以覆蓋(子類中如果建立了一個與父類別中相同名稱、相同返回值型別、相同參數列的方法,只是方法體中的實現不同,以實現不同於父類別的功能,這種方式被稱為方法重寫,又稱為方法覆蓋。這裡了解即可,教學後面我們會詳細講解)一個 private 或者是 static 的方法?

“static”關鍵字表明一個成員變數或者是成員方法可以在沒有所屬的類的範例變數的情況下被存取。

Java 中 static 方法不能被覆蓋,因為方法覆蓋是基於執行時動態系結的,而 static 方法是編譯時靜態系結的。static 方法跟類的任何範例都不相關,所以概念上不適用。

3)是否可以在 static 環境中存取非 static 變數?

static 變數在 Java 中是屬於類的,它在所有的範例中的值是一樣的。當類被 Java 虛擬機器載入的時候,會對 static 變數進行初始化。如果你的程式碼嘗試不用範例來存取非 static 的變數,編譯器會報錯,因為這些變數還沒有被建立出來,還沒有跟任何範例關聯上。

4)static 靜態方法能不能參照非靜態資源?

不能,new 的時候才會產生的東西,對於初始化後就存在的靜態資源來說,不能參照它。

5)static 靜態方法裡面能不能參照靜態資源?

可以,因為都是類初始化的時候載入的。

6)非靜態方法裡面能不能參照靜態資源?

可以,非靜態方法就是實體方法,那是 new 之後才產生的,那麼屬於類的內容它都認識。

使用誤區

1)static 關鍵字會改變類中成員的存取許可權嗎?

有些初學者會將 Java 中的 static 與 C/C++ 中的 static 關鍵字的功能混淆了。在這裡只需要記住一點,與 C/C++ 中的 static 不同,Java 中的 static 關鍵字不會影響到變數或者方法的作用域。在 Java 中能夠影響到存取許可權的只有 private、public、protected、friendly 這幾個關鍵字。看下面的例子就明白了:

定義一個 Student 類,程式碼如下:
public class Student {
    public static String name = "張三";
    private static int age = 10;
}
定義 Main 類呼叫 Student 類的 age 屬性,程式碼如下:
public class Main {
    public static void main(String[] args) {
        System.out.println(Student.name);
        System.out.println(Student.age);
    }
}
程式碼第 4 行會提示錯誤“Student.age 不可視(The field Student.age is not visible)”,這說明 static 關鍵字並不會改變變數和方法的存取許可權。 

2)能通過 this 存取靜態成員變數嗎?

雖然對於靜態方法來說沒有 this,那麼在非靜態方法中能夠通過 this 存取靜態成員變數嗎?先看下面的一個例子,這段程式碼輸出的結果是什麼? 
public class Main {
    static int value = 33;

    public static void main(String[] args) throws Exception {
        new Main().printValue();
    }

    private void printValue() {
        int value = 3;
        System.out.println(this.value);    // 輸出 33
    }
}
這裡面主要考察 this 和 static 的理解。this 代表什麼?this 代表當前物件,那麼通過 new Main() 來呼叫 printValue 的話,當前物件就是通過 new Main() 生成的物件。而 static 變數是被物件所享有的,因此在 printValue 中的 this.value 的值毫無疑問是 33。在 printValue 方法內部的 value 是區域性變數,根本不可能與 this 關聯,所以輸出結果是 33。在這裡永遠要記住一點:靜態成員變數雖然獨立於物件,但是不代表不可以通過物件去存取,所有的靜態方法和靜態變數都可以通過物件存取(只要存取許可權足夠)。  

3)static 能作用於區域性變數麼?

在 C/C++ 中 static 是可以作用域區域性變數的,但是在 Java 中切記,Java 語法規定 static 是不允許用來修飾區域性變數。