CodeGym /Java Blog /Toto sisi /關於 Java 靜態修飾符你需要知道的 10 件事
John Squirrels
等級 41
San Francisco

關於 Java 靜態修飾符你需要知道的 10 件事

在 Toto sisi 群組發布
在 Java 中,static 修飾符表示與類直接相關的東西:如果一個字段是靜態的,那麼它屬於該類;如果一個方法是靜態的,那麼它就屬於這個類。因此,您可以使用類的名稱來調用靜態方法或引用靜態字段。例如,如果該count字段在Counter類中是靜態的,則意味著您可以使用以下表達式引用該變量:Counter.count. 關於 Java 中的靜態修飾符你需要知道的 10 件事 - 1當然,必須考慮訪問修飾符。例如,private字段僅在聲明它們的類中可用。並且protected字段可用於包內的所有類,以及包外的所有子類。假設該類Counter有一個靜態increment()方法,其工作是遞增count場地。要調用此方法,您可以使用Counter.increment(). 無需創建類的實例Counter來訪問靜態字段或方法。這是靜態(類)變量和方法與非靜態(實例)變量和方法之間的根本區別。一個重要的注意事項。不要忘記類的靜態成員直接屬於類,而不是類的任何實例。也就是說,靜態count變量的值對於所有對像都是相同的Counter。在本文中,我們將了解在 Java 中使用靜態修飾符的基本方面,以及一些有助於您理解關鍵編程概念的功能。

每個程序員都應該了解 Java 中的靜態修飾符。

在本節中,我們將了解使用靜態方法、字段和類的主要方面。讓我們從變量開始。
  1. 您不能在靜態上下文中訪問類的非靜態成員,例如靜態方法或塊。編譯下面的代碼將導致錯誤:

    
    public class Counter {
    private int count;
    public static void main(String args []) {
       System.out.println(count); //  Compile time error
    }
    }
    

    這是 Java 程序員尤其是新手最常犯的錯誤之一。由於main方法是靜態的而count變量不是,在方法println內部使用方法main會產生“編譯時錯誤”。

  2. 與局部變量不同,靜態字段和方法不在thread safeJava 中。實際上,這是多線程編程中安全問題最常見的原因之一。考慮到類的每個實例都引用靜態變量的相同副本,這樣的變量需要被類保護或“鎖定”。因此,在使用靜態變量時,一定要正確使用synchronized,以免出現race conditions.

  3. 靜態方法有一個實用的優點,那就是不需要在每次調用它們時都創建一個新對象。可以使用聲明它的類的名稱來調用靜態方法。這就是為什麼這些方法非常適合factory方法和utility方法。該類java.lang.Math是一個很好的例子:它的幾乎所有方法都是靜態的。Java 的實用程序類被標記final為同樣的原因。

  4. 另一個要點是你不能覆蓋 ( @Override) 靜態方法。如果您在 a 中聲明這樣一個方法subclass,即具有相同名稱和簽名的方法,您只是“隱藏”了該方法superclass而不是覆蓋它。這種現像被稱為method hiding。這意味著如果在父類和子類中都聲明了靜態方法,那麼在編譯時調用的方法將始終基於變量類型。與方法覆蓋不同,此類方法不會在程序運行時執行。讓我們考慮一個例子:

    
    class Vehicle {
         public static void kmToMiles(int km) {
              System.out.println("Inside the parent class / static method");
         } 
    }
    
    class Car extends Vehicle {
         public static void kmToMiles(int km) {
              System.out.println("Inside the child class / static method");
         } 
    }
    
    public class Demo {   
       public static void main(String args []) {
          Vehicle v = new Car();
           v.kmToMiles(10);
      }
    }
    

    控制台輸出:

    父類/靜態方法內部

    該代碼清楚地表明,儘管對像是 a ,但還是調用了類Car中的靜態方法,因為該方法是在編譯時調用的。Vehicle請注意,沒有編譯錯誤!

  5. 此外,除了頂級類之外,您還可以將類聲明為靜態的。這樣的類被稱為nested static classes. 它們對於提供更好的凝聚力很有用。嵌套靜態類的一個顯著例子是HashMap.Entry,它裡面是一個數據結構HashMap。值得注意的是,與內部類一樣,靜態嵌套類是在單獨的 .class 文件中聲明的。因此,如果您在主類中聲明了五個嵌套類,您將擁有 6 個擴展名為 .class 的文件。另一個例子是我們自己的聲明Comparator,比如類AgeComparator中的一個年齡比較器()Employee

  6. static 修飾符也可以在靜態塊中指定,更好地稱為“靜態初始化塊”,它在加載類時執行。如果您不聲明這樣的塊,Java 會將所有靜態字段收集到一個列表中,並在加載類時初始化它們。靜態塊不能拋出已檢查的異常,但它可以拋出未經檢查的異常。在這種情況下,ExceptionInInitializerError將發生。實際上,在靜態字段初始化期間發生的任何異常都會被 Java 包裝在這個錯誤中。這也是最常見的原因NoClassDefFoundError,因為類在被引用時不會在內存中。

  7. 知道靜態方法在編譯時鏈接是很有用的,這與虛擬或非靜態方法的鏈接不同,後者在運行時在真實對像上調用時鏈接。因此,在 Java 中不能覆蓋靜態方法,因為多態性在運行時不適用於它們。這是聲明靜態方法時要考慮的一個重要限制。僅當沒有能力或不需要覆蓋子類中的方法時,這樣做才有意義。工廠方法和實用方法是正確使用靜態修飾符的好例子。Joshua Bloch在他的《Effective Java》一書中指出了靜態工廠方法相對於構造函數的幾個優勢,這是每個 Java 程序員必讀的一本書。

  8. 初始化是靜態塊的一個重要方面。靜態字段或變量在類加載到內存後進行初始化。初始化的順序是從上到下,與它們在Java類的源文件中聲明的順序相同。由於靜態字段以線程安全的方式初始化,因此該過程也用於實現該Singleton模式。如果您出於某種原因不使用Enumas a Singleton,那麼您有一個很好的選擇。但在這種情況下,您必須考慮到這不是“惰性”初始化。這意味著靜態字段甚至在有人“請求”它之前就已經被初始化了。如果一個對象佔用大量資源或很少使用,那麼在靜態塊中初始化它對您不利。

  9. 在序列化期間,靜態字段(如transient變量)不會被序列化。事實上,如果您將任何數據保存在靜態字段中,它在反序列化後將包含其初始(默認)值。例如,如果靜態字段是int,則其值在反序列化後將為零。如果其類型為float,則該值為 0.0。如果字段是Object,則值將為null。老實說,這是 Java 職位面試中關於序列化的最常見問題之一。不要將基本對像數據存儲在靜態字段中!

  10. 最後說一下靜態導入。此修飾符與標準語句有很多共同之處import,但不同之處在於它允許您導入一個或所有靜態類成員。一旦導入了靜態方法,就可以像在同一個類中聲明一樣訪問它們。同樣,通過引入靜態字段,我們可以在不指定類名的情況下訪問它們。這個特性出現在 Java 1.5 中,如果使用得當,可以提高代碼的可讀性。這種構造最常出現在 JUnit 測試中,因為幾乎所有測試開發人員都對斷言方法(例如assertEquals()及其重載變體)使用靜態導入。

  11. 目前為止就這樣了。每個 Java 程序員都需要了解上面提到的靜態修飾符的所有方面。本文回顧了有關靜態變量、字段、方法、初始化塊和導入的基本信息。它還涉及一些重要的屬性,這些屬性對於編寫和理解 Java 程序是必不可少的。我希望每個開發人員都能完善他們對靜態成員的熟練使用,因為這對於認真的軟件開發非常重要。”

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION