C#的類定義中可以包含兩種方法:靜態和非靜態的。使用了static修飾符的方法為靜態方法,反之則是非靜態的。
靜態方法是一種特殊的成員方法,它不屬於類的某一個具體的實例。非靜態方法可以訪問類中的任何成員,而靜態只能訪問類中的靜態成員。看這個例子:
class A { int x; static int y; static int F(){ x=1; //錯誤,不允許訪問 y=2; //正確,允許訪問 }
在這個類定義中,靜態方法F()可以訪問類中靜態成員y,但不能訪問非靜態成員x。這是因為,x作為非靜態成員,在類的每個實例中都占有一個存儲(或者說具有一個副本),而靜態方法是類所共享的,它無法判斷出當前的x是屬於哪個類的實例,所以不知道應該到內存的哪個地址去讀取當前x的值。而y是靜態成員,所有類的實例都公用一個副本,靜態方法F使用它就不存在什麼問題。
那麼,是不是靜態方法就無法識別類的實例了呢?在C#中,我們可以靈活地采用傳遞參數的辦法。第十章我們提到了一個Windows窗口的例子,這裡我們再對這個例子進行一些改變。
程序清單11-6:
using System; class Window { public string m_caption; //窗口的標題 public bool IsActive; //判斷是否被激活 public handle m_handle; //窗口的句柄 public static int m_total; //當前打開的窗口數目 public handle Window(){ m_total++; //窗口總數加1 //......創建窗口的一些執行代碼 return m_handle; //窗口的返回值作為句柄 } ~Window(){ m_total--; //窗口總數減1 //......撤消窗口的一些執行代碼 } public static string GetWindowCaption(Window w) { return w.m_caption; } //......窗口的其它成員 }
分析一下上面例子中的代碼。每個窗口都有窗口標題m_caption、窗口句柄m_handle、窗口是否激活IsActive三個非靜態的數據成員(窗口句柄是Windows操作系統中保存窗口相關信息的一種數據結構,我們在這個例子中簡化了對句柄的使用)。系統中總共打開的窗口數目m_total作為一個靜態成員。每個窗口調用構造函數創建,這時m_total的值加1。窗口關閉或因為其它行為撤消時,通過析構函數m_total的值減1.
我們要注意窗口類的靜態方法GetWindowCaption(Window w)。這裡它通過參數w將對象傳遞給方法執行,這樣它就可以通過具體的類的實例指明調用的對象,這時它可以訪問具體實例中的成員,無論是靜態成員還是非靜態成員。