文章目錄
1.靜態成員、實例成員
2.靜態類
3.類的靜態成員和非靜態成員區別
--------------------------------------分割線---------------------------------------------
1.靜態成員、實例成員
1.1定義及說明
數據成員:
靜態成員:靜態成員變量是和類相關聯的,可以作為類中"共"有的變量(是一個共性的表現),他不依賴特定對象的存在,訪問的時候通過類名加點操作符加變量名來訪問.
實例成員:實例成員變量是和對象相關聯的,訪問實例成員變量依賴於實例的存在.
函數成員:
靜態方法:靜態方法是不屬於特定對象的方法,靜態方法可以訪問靜態成員變量和靜態方法;靜態方法不可以直接訪問實例變量和實例方法,可以間接調用,首先要創建一個類的實例,然后通過這一特定對象來調用靜態方法;
實例方法:一個實例方法的執行與特定對象關聯,他的執行需要一個對象存在。實例方法可以直接訪問靜態變量和實例變量,當多個實例對象存在時,內存中並不是存在美個特定的實例方法的拷貝,而是,相同類的所有對象都共享每個實例方法的一個拷貝(實例方法只占用“一套”空間)。
靜態成員變量 | 靜態方法 | 實例成員變量 | 實例方法 | |
靜態方法 | 直接訪問 | 直接訪問 | 不可直接訪問 | 不可直接訪問 |
實例方法 | 直接訪問 | 直接訪問 | 直接訪問 | 直接訪問 |
總之:實例方法的存在必須要有對象實例的存在,如果對象實例不存在,則實例方法也就沒有調用它的主人。靜態方法的存在前提是類的存在,所以無需聲明和New對象。
1.2代碼演示


class Program { static void Main(string[] args) { Class1.CallObjectFunc();//靜態調用 Console.WriteLine(Environment.NewLine); Class1 tmpClass = new Class1();//實例調用 tmpClass.ObjectFunc(); Console.ReadKey(); } } class Class1 { static int Class_m = 9;//靜態成員 private int object_m = 8;//實例成員 public static void CallObjectFunc() { Console.WriteLine("------------靜態方法調用開始:"); Class1 class1 = new Class1(); class1.ObjectFunc(); Console.WriteLine("object_m:" + class1.object_m.ToString()); Console.WriteLine("------------靜態方法調用結束:"); } public void ObjectFunc() { Console.WriteLine("實例方法調用開始:"); Console.WriteLine("Class_m:" + Class_m.ToString()); Console.WriteLine("實例方法調用結束:"); } }
輸出結果:
2.靜態類
靜態類的主要功能如下:
-
它們僅包含靜態成員。----函數成員和變量都必須有static修飾
-
它們不能被實例化。
-
它們是密封的。-----------編譯器編譯時自動生成sealed標記
-
它們不能包含實例構造函數。
因此創建靜態類與創建僅包含靜態成員和私有構造函數的類大致一樣。私有構造函數阻止類被實例化。
使用靜態類的優點在於,編譯器能夠執行檢查以確保不致偶然地添加實例成員。編譯器將保證不會創建此類的實利。
靜態類是密封的,因此不可被繼承。靜態類不能包含構造函數,但仍可聲明靜態構造函數以分配初始值或設置某個靜態狀態。
靜態類:


static class CompanyInfo { public static string GetCompanyName() { return "CompanyName"; } public static string GetCompanyAddress() { return "CompanyAddress"; } }
3.類的靜態成員和非靜態成員區別
3.1區別
(1)語法區別:靜態成員有關鍵字static,非靜態成員無static修飾;
(2)存儲區別: 靜態成員變量存儲位於程序的全局變量存儲區,其作用域限制為類內部,並且在整個程序運行期間只在內存中擁有一個存儲位置,不會拷貝不會復制,只是一個;
非靜態成員變量存儲位於對象的變量存儲區,多個對象擁有多個變量的存儲,只隸屬於自己的的對象
(3)歸屬區別:靜態成員隸屬於類,是類的財產,無論對一個類創建多少個實例,它的靜態成員都只有一個副本,在各個地方的改變都會改變其值;
非靜態成員隸屬於它的對象,各自對象同一個非靜態成員值的改變都不互相影響,有多少實例就有多少副本;
(4)生存周期區別: 知道了存儲位置的區別也就不難理解生存周期的差異了,靜態成員只要分配了空間則在整個程序運行期間,它都是存在的,只有程序關閉之后,它的內存才會被GC回收器收回,不過作用域仍然只限制於類的內部,在類外部調用時需要使用類 名加點的方式訪問;
類的非靜態成員的生存周期跟隨於隸屬於對象的生存周期,對象消亡則非靜態成員就會被回收;
(5)初始化順序的區別:初始化都是最先初始化類的靜態成員,然后才是非靜態數據成員。
3.2代碼:
下面代碼的輸出是多少呢?先自己思考


using System; using System.Collections.Generic; using System.Linq; using System.Text; class class1 { private static int i = getNum(); private static int num = 1; int j = getNum(); private static int getNum() { return num; } static void Main(string[] args) { Console.WriteLine("i={0}", i); class1 class1Object = new class1();//默認構造函數 Console.WriteLine("j={0}", class1Object.j); Console.WriteLine("i={0}", i); Console.ReadKey(); } }
輸出結果為:
額,怎么回事這樣呢?是不是會和你想的不一樣,如果你真有這種想法,說明還需要看我下面的分析噢
代碼分析
類結構:這個類有三個變量,兩個私有靜態成員變量i和num,一個非靜態成員變量j;一個私有靜態函數getNum(),一個函數入口Main()
程序執行過程:首先之前說了初始化會首先初始化類的靜態變量。
i分配空間並初始化值為0-->num分配空間並初始化為0-->i賦值(調用getNum函數,此時num為0,返回值為0,所以i=0)-->num賦值為1-->Main函數
至於Main函數內執行時,為什么i輸出不是1呢?這是因為靜態成員只初始化一次,所以此時調用i並不會再調用getNum()函數為其賦值,此時的調用i是獲取i分配空間上的值。