iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 2
1
自我挑戰組

開發雜記系列 第 3

為甚麼要宣告static

前言

甚麼時候用類別點(.),甚麼是後用變數點(.)?點出來的東西怎麼都不一樣?這個問題曾經困擾了筆者很久。如下案例:

String.IsNullOrEmpty("ITHome_Ironman_2017");
String demo = "ITHome_Ironman_2017";
demo = demo.ToUpper();

後來筆者才搞懂String.IsNullOrEmpty()是靜態方法static function。同樣的案例發身在C/C++、JAVA身上都有。筆者身邊有一些朋友一直搞不懂這是甚麼意思,本篇就此問題來做討論。

原理

事實上,所有的程式被組譯後都可以得到程式/物件的大小,當OS啟動該程式的時候,就會將程式掛載在記憶體中,並且賦予一個記憶體位置,並跳躍至該程式的啟動區域執行。而當程式中出現new的時候,會跟記憶體申請記憶體空間,當記憶體擁有對應的大小的記憶時就會將其提供給該程式使用,而該程式也能針對該區域的記憶體進行讀寫。
而static變數就是在載入程式後會主動配給記憶體給程式(僅一次),後續無論實例化多少次,記憶體位置都一樣。
其實,函式在最後組譯後其實是一個記憶體位置(32/64bits),藉由這個特性靜態方法也有同樣的效果。

使用方式

使用static關鍵字可以讓程式被OS載入時就被儲存於記憶體中,直到Application結束為止。如下:

private static float PI = 0.0f;  //靜態變數
private float radius = 0.0f;     //一般變數

值得特別說明的是,如果您將一個靜態變數定義在一個物件中,您可以利用靜態建構函式來初始化靜態變數。
注意:靜態建構函式只會執行一次

優缺點

實務上,通常會將公共變數全部設定為靜態變數,例如上述物件中含有一個PI的定義。這樣可以共享記憶體,相對較節省記憶體。但事情總是有兩面性的,也因為共享記憶體,所以要特別注意存取權限以及存取時機,例如:通常不會在建構式中設定靜態變數,以免造成其他程式誤取。

驗證

為了證明靜態建構式只會存取一次,筆者撰寫測試代碼如下。

原始碼
//filename : Circle.cs
public class Circle
{
    private static float PI = 0.0f;
    private float radius = 0.0f;
    static Circle()
    {
        Console.WriteLine("靜態建構函式-啟動");
        PI = 3.141592653f;       
    }
    public Circle(float radius)
    {
        Console.WriteLine("建構函式-啟動");
        this.radius = radius;
    }
    public float getArea() { return PI * this.radius * this.radius; }
}
//filename : Program.cs
class Program
{
    static void Main(string[] args)
    {
        Circle circle1 = new Circle(3.0f);
        Circle circle2 = new Circle(5.0f);
        Console.WriteLine(circle1.getArea());
        Console.WriteLine(circle2.getArea());

        Console.ReadKey();
    }
}
執行結果

執行結果
如上,雖然我們new了兩次變數,但是靜態建構式只有執行一次。再次驗證靜態變數會共享資料。

後記

事實上,如果您擅長使用C/C++,您可以直接利用sizeof()來驗證物件是否共用記憶體。有關證明方式有機會筆者改天再行討論。

參考資料

MSDN
靜態類別和靜態類別成員
靜態建構函式


上一篇
cs檔分身術:partial class
下一篇
大家遺忘的enum
系列文
開發雜記4

1 則留言

1
yukine23329626
iT邦新手 5 級 ‧ 2019-03-17 20:49:23

這篇文章應該是 C# 的,我這邊補充 JAVA 的
java class 裡的 constructor 似乎不能以 static 修飾之
會有如下的錯誤訊息:
.\Circle.java:6: error: modifier static not allowed here
static Circle()
^
1 error

以我的理解是,受到 static 修飾的 class 成員,只屬於那個 class,不會被繼承。
所以像是 constructor 這樣會被 subclass object 呼叫的成員,無法用 static 修飾之。

references:
https://beginnersbook.com/2013/05/static-constructor/
https://stackoverflow.com/questions/10291949/are-static-methods-inherited-in-java

感謝您的補充~

我要留言

立即登入留言