《隨筆五》——C#中的 —— “ 靜態成員的生存期 、靜態成員函式、成員常量”
阿新 • • 發佈:2018-11-17
目錄
先看一個靜態欄位的示例:
namespace Ch05Ex03 { class Persion { int Mem1; static int Mem2; //私有靜態成員 static Persion() { Mem2 = 900; //Mem1 = 200; //不可以在靜態建構函式中初始化 非靜態欄位 WriteLine("靜態建構函式被呼叫!\n"); } public Persion(int aa,int bb) { Mem1 = aa; Mem2 = bb; //利用建構函式設定私有靜態成員 WriteLine("\n例項建構函式被呼叫!\n"); } public void SetVars(int v1,int v2) { Mem1 = v1; Mem2 = v2; } public void Display(string str) { WriteLine($"{str}: Mem1的值:{Mem1}, Mem2的值:{Mem2}"); } } class Program { static void Main(string[] args) { Persion d1 = new Persion(2, 8); //利用公有建構函式設定靜態欄位和普通欄位的值 d1.Display("d1"); Persion d2 = new Persion(5, 77); d2.Display("d2"); WriteLine(); d1.SetVars(7, 22); //利用公有成員函式設定靜態欄位和普通欄位的值 d1.Display("d1"); d2.SetVars(99, 100); d2.Display("d2"); d1.Display("d1"); //這裡再次輸出d1的值,輸出就是 7,100,因為它被d2 改變了 // 注意下面的程式碼: Persion d3 = new Persion(141, 55), d4 = new Persion(454, 666); /*該程式碼輸出: * d3: Mem1的值:141, Mem2的值:666 d4: Mem1的值:454, Mem2的值:666 為什麼d3的值是141和666, 而不是141,55 呢? 首先執行該程式碼的時候我們呼叫例項建構函式執行成員初始化,我們首先初始化例項d3的成員,然後設定 d4的成員 ,設定d3的時候我們初始化Mem1為141,Mem2 = 55, 設定d4的值時初始化Mem1為454. Mem2 = 666. 因為靜態欄位被類的所有例項所共享, 所有例項都訪問同一記憶體位置。因此d4把靜態欄位Mem2的值改變了, 因此 d3的 Mem2 的值也改變了。*/ d3.Display("d3"); d4.Display("d4"); ReadKey(); } } } 輸出結果為: 靜態建構函式被呼叫! 例項建構函式被呼叫! d1: Mem1的值:2, Mem2的值:8 例項建構函式被呼叫! d2: Mem1的值:5, Mem2的值:77 d1: Mem1的值:7, Mem2的值:22 d2: Mem1的值:99, Mem2的值:100 d1: Mem1的值:7, Mem2的值:100 例項建構函式被呼叫! 例項建構函式被呼叫! d3: Mem1的值:141, Mem2的值:666 d4: Mem1的值:454, Mem2的值:666
那為什麼沒有輸出靜態建構函式中設定的值呢,道理都是一樣的,程式首先呼叫的就是靜態建構函式,呼叫之後 Mem2 = 900; Mem1=0; 記住: 不管這個類有多少個類例項, 靜態建構函式只調用一次。
然後就呼叫例項建構函式,例項建構函式設定的值直接覆蓋了靜態建構函式中的值,所以輸不出靜態建構函式設定的值。
靜態成員的生命期
● 只有在例項建立之後才產生例項成員,在例項銷燬後例項成員就不存在了。
● 但靜態成員,即使類沒有例項,也存在靜態成員,並且可以訪問。(在C++中不可以這樣)
namespace Ch05Ex03 { class D { static public int Mem2; //但是如果設定為私有的靜態成員,就不可以在類外通過類直接訪問 } class Program { static void Main(string[] args) { D.Mem2 = 5; //通過類名直接為公有靜態資料成員賦值, 但是如果該成員是私有,就不可以這樣賦值 WriteLine(D.Mem2); ReadKey(); } } } 輸出結果為: 5
注意: 靜態成員即使沒有類的例項也存在。如果該靜態欄位有初始化語句,那麼會在使用該類的任何靜態成員之前初始化該欄位, 但沒必要在程式執行的開始就初始化。
靜態成員函式
● 如同靜態欄位,靜態成員函式獨立於任何類例項。 即使沒有類的例項,仍然可以呼叫靜態方法。(C++中不可以這樣)
● 注意:類成員函式(無論是static成員函式或非static成員函式)都可以直接訪問static資料成員,static 成員函式僅能訪問static 資料成員,不能訪問非static的資料成員,也不能訪問非static 的成員函式。
namespace Ch05Ex03 { class D { static public int Mem2; public int aa = 10; //在類定義中初始化一個非靜態的公有成員 static public void PrintVal() //靜態成員函式訪問靜態成員資料 { WriteLine(Mem2); //WriteLine(aa); 靜態成員不可以訪問非靜態資料成員 } public void getVal() { WriteLine(aa); // 輸出aa的值 WriteLine(Mem2); //非靜態函式可以訪問靜態的資料成員 } } class Program { static void Main(string[] args) { D.Mem2 = 5; D.PrintVal(); D dd = new D(); // 建立該類的物件 dd.getVal(); ReadKey(); } } } 輸出結果為: 5 10 5
在C++中可以宣告常量為靜態的常量成員資料, 而在C#中卻不可以。
與C++不同,在C#中沒有全域性常量。 每個常量都必須宣告在型別內。
成員常量
namespace Ch05Ex03
{
class D
{
//用於初始化常量的值必須是在編譯時就可以確定的,通常是一個簡單型別的值或者一個表示式
const int Mem2 = 5;
const int Mem3 = 2 * Mem2; // 正確, 但是Mem2 必須是一個const欄位,否則錯誤。
}
class Program
{
static void Main(string[] args)
{
ReadKey();
}
}
}
常量與靜態量
● 注意: 常量成員即使沒有類的例項也可以使用。 與真正的靜態量不同, 常量沒有自己的儲存位置, 而是在編譯時被編譯器替換。 跟C++中的 #define 類似。
看一個C++的程式:
class D
{
public:
const double PI = 3.14;
D(decltype(PI) aa):PI(aa)
{
}
};
int main()
{
D dd(22.3);
cout << dd.PI << endl;
system("pause");
return 0;
}
看一個C#程式:
namespace Ch05Ex03
{
class D
{
public const double PI = 3.14;
}
class Program
{
static void Main(string[] args)
{
WriteLine(D.PI); //利用類例項訪問公有常量資料成員
ReadKey();
}
}
}
在C#中常量成欄位現得像一個靜態量, 但不能將常量欄位宣告成 static:
static const double PI = 3.14; //錯誤
但是在C++中可以。