文章目錄
7.5 靜態成員與執行個體成員
在類的成員的類型或者傳回值類型前面加上關鍵字static,就能將該成員定義為靜態成員(static member)。常量或型別宣告會隱式地聲明為靜態成員,其他沒有用static修飾的成員都是執行個體成員(instance member)或者稱為非靜態成員。靜態成員屬於類,被這個類的所有執行個體所共用;執行個體成員屬於對象(類的執行個體),每一個對象都有執行個體成員的不同副本。
靜態成員具有下列特徵:
— 靜態成員必須通過類名使用 . 運算子來引用,而不能用對象來引用。
— 一個靜態欄位只標識一個儲存位置。無論建立了一個類的多少個執行個體,它的靜態欄位在記憶體中都只佔同一塊地區。
— 靜態函數成員(方法、屬性、事件、運算子或建構函式)不能作用於具體的執行個體,在這類函數成員中不能直接使用執行個體成員,必須通過類名來引用。
執行個體成員具有以下特點:
— 執行個體成員必須通過對象名使用 . 運算子來引用,而不能用類名來引用。
— 類的執行個體欄位屬於類的執行個體所有,每建立一個類的執行個體,都在記憶體中為執行個體欄位開闢了一塊地區。類的每個執行個體分別包含一組該類的所有執行個體欄位的副本。
— 執行個體函數成員(方法、屬性、索引器、執行個體建構函式或解構函式)作用於類的給定執行個體,在它們的代碼體內可以直接引用類的靜態和執行個體成員。
其實,我們在前面的幾章中大量使用的Console類的WriteLine等方法都是靜態方法,都是通過類名Console來引用的。
理解下面的代碼,體會靜態成員和執行個體成員的使用方法:
class Test
{
int x; // 執行個體欄位
static int y; // 靜態欄位
void F() // 執行個體方法
{
x = 1; // 正確:執行個體方法內可以直接引用執行個體欄位
y = 1; // 正確:執行個體方法內可以直接引用靜態欄位
}
static void G() // 靜態方法
{
x = 1; // 錯誤:靜態方法內不能直接引用執行個體欄位
y = 1; // 正確:靜態方法可以直接引用靜態欄位
}
static void Main() // 靜態方法
{
Test t = new Test(); // 建立對象
t.x = 1; // 正確:用對象引用執行個體欄位
t.y = 1; // 錯誤:不能用對象名引用靜態欄位
Test.x = 1; // 錯誤:不能用類名引用執行個體欄位
Test.y = 1; // 正確:用類名引用靜態欄位
t.F(); // 正確:用對象調用執行個體方法
t.G(); // 錯誤:不能用對象名調用靜態方法
Test.F(); // 錯誤:不能用類名調用執行個體方法
Test.G(); // 正確:用類名調用靜態方法
}
}
注意 上述代碼中,Main也是Test類的靜態方法,可以在其中直接使用靜態成員,而不需要使用類名來引用。
下面的程式示範了靜態欄位的性質:
// StaticMember.cs
// 靜態欄位的例子
using System;
public class Count
{
static int count;
int number;
public Count()
{
count = count + 1;
number = count;
}
public void show()
{
Console.WriteLine("object{0} : count={1}", number, count);
}
}
class Test
{
public static void Main()
{
Count a = new Count();
a.show();
Console.WriteLine("-----------------");
Count b = new Count();
a.show();
b.show();
Console.WriteLine("-----------------");
Count c = new Count();
a.show();
b.show();
c.show();
}
}
其輸出結果為:
object1 : count=1
-----------------
object1 : count=2
object2 : count=2
-----------------
object1 : count=3
object2 : count=3
object3 : count=3
從上面的例子中可以看出,無論何時,類的所有執行個體的靜態欄位count的值都是相同的,一個執行個體改變了它的值,其他執行個體得到的值也將隨之變化,說明所有執行個體都使用同一個count欄位;而每個執行個體的成員欄位number的值都是不同的,也不能被其他的執行個體化改變。