我們天天都在使用
Console.WriteLine("Hello world"); ? Console.ReadLine(""); ? Arrays.Sort()
為什么Console 類 調(diào)用 方法不需要實(shí)例化而可以直接調(diào)用呢?
我們可以查看Console的源碼發(fā)現(xiàn)Console類定義如下:
public static class Console { // ... }
我們發(fā)現(xiàn) Console 類 前面有個(gè) static 關(guān)鍵字修飾, 我們把 static 修飾的類 叫作 靜態(tài)類
1. 靜態(tài)類
static關(guān)鍵字的作用
-
static是靜態(tài)的意思,可以修飾成員變量和成員方法。
-
static修飾成員變量表示該成員變量只在內(nèi)存中只存儲(chǔ)一份,可以被共享訪問、修改。
public static class MyConsole { // 靜態(tài)構(gòu)造方法 static MyConsole() { } // 靜態(tài)變量 public static string Title { get; set; } public static string Description { get; set; } // 靜態(tài)方法 public static void WriteLine(params string[] s) { } } class Program { static void Main(string[] args) { MyConsole.Title = "Hello,靜態(tài)類"; MyConsole.WriteLine("靜態(tài)方法調(diào)用"); } }
?
靜態(tài)類基本上與非靜態(tài)類相同,但存在一個(gè)差異:靜態(tài)類無法實(shí)例化。 換句話說,無法使用
與所有類類型的情況一樣,加載引用該類的程序時(shí),.NET 運(yùn)行時(shí)會(huì)加載靜態(tài)類的類型信息。 程序無法確切指定類加載的時(shí)間。 但是,可保證進(jìn)行加載,以及在程序中首次引用類之前初始化其字段并調(diào)用其靜態(tài)構(gòu)造函數(shù)。 靜態(tài)構(gòu)造函數(shù)只調(diào)用一次,在程序所駐留的應(yīng)用程序域的生存期內(nèi),靜態(tài)類會(huì)保留在內(nèi)存中。
?
以下列表提供靜態(tài)類的主要功能:
-
只包含靜態(tài)成員。
-
無法進(jìn)行實(shí)例化。
-
會(huì)進(jìn)行密封。
-
不能包含
因此,創(chuàng)建靜態(tài)類基本上與創(chuàng)建只包含靜態(tài)成員和私有構(gòu)造函數(shù)的類相同。 私有構(gòu)造函數(shù)可防止類進(jìn)行實(shí)例化。 使用靜態(tài)類的優(yōu)點(diǎn)是編譯器可以進(jìn)行檢查,以確保不會(huì)意外地添加任何實(shí)例成員。 編譯器可保證無法創(chuàng)建此類的實(shí)例。
靜態(tài)類會(huì)進(jìn)行密封,因此不能繼承。 它們不能繼承自任何類(除了
2. 非靜態(tài)類的靜態(tài)成員
非靜態(tài)類
不被static 關(guān)鍵字修飾的類稱為非靜態(tài)類.
?
非靜態(tài)類可以包含靜態(tài)方法、字段、屬性或事件。 即使未創(chuàng)建類的任何實(shí)例,也可對(duì)類調(diào)用靜態(tài)成員。 靜態(tài)成員始終按類名(而不是實(shí)例名稱)進(jìn)行訪問。 靜態(tài)成員只有一個(gè)副本存在(與創(chuàng)建的類的實(shí)例數(shù)無關(guān))。 靜態(tài)方法和屬性無法在其包含類型中訪問非靜態(tài)字段和事件,它們無法訪問任何對(duì)象的實(shí)例變量,除非在方法參數(shù)中顯式傳遞它。
更典型的做法是聲明具有一些靜態(tài)成員的非靜態(tài)類(而不是將整個(gè)類都聲明為靜態(tài))。 靜態(tài)字段的兩個(gè)常見用途是保留已實(shí)例化的對(duì)象數(shù)的計(jì)數(shù),或是存儲(chǔ)必須在所有實(shí)例間共享的值。
靜態(tài)方法可以進(jìn)行重載,但不能進(jìn)行替代,因?yàn)樗鼈儗儆陬?,而不屬于類的任何?shí)例。
雖然字段不能聲明為 static const
,不過 static const
字段在其行為方面本質(zhì)上是靜態(tài)的。 它屬于類型,而不屬于類型的實(shí)例。 因此,可以使用用于靜態(tài)字段的相同 ClassName.MemberName
表示法來訪問 const
字段。 無需進(jìn)行對(duì)象實(shí)例化。
C# 不支持靜態(tài)局部變量(即在方法范圍中聲明的變量)。
可在成員的返回類型之前使用 static
關(guān)鍵字聲明靜態(tài)類成員,如下面的示例所示:
public class Cat // 非靜態(tài)類 { public string Name { get; set; } // 實(shí)例變量,屬于對(duì)象 public static int Leg { get; set; } // 靜態(tài)成員變量,, 屬于類 // 重載靜態(tài)方法run, 屬于類 public static void Run() { // Console.WriteLine(this.Name);// 報(bào)錯(cuò),靜態(tài)方法中,不能訪問實(shí)例成員 Console.WriteLine($"{Leg} 條腿的貓?jiān)谂懿?/span>");// 正確,靜態(tài)類中可以訪問靜態(tài)成員變量 } // 重載靜態(tài)方法run, 屬于類 public static void Run(int speed) { Console.WriteLine($"{Leg} 條腿的貓?jiān)谂懿?,速度是:{speed}"); } // 實(shí)例方法,屬于對(duì)象 public void Eat() { // 實(shí)例方法既可以訪問成員變量,也可以訪問靜態(tài)變量 Console.WriteLine($"{Leg} 條腿的 {this.Name} 在搶狗糧吃。") ; } }
?
在首次訪問靜態(tài)成員之前以及在調(diào)用構(gòu)造函數(shù)(如果有)之前,會(huì)初始化靜態(tài)成員。 若要訪問靜態(tài)類成員,請(qǐng)使用類的名稱(而不是變量名稱)指定成員的位置,如下面的示例所示:
static void Main(string[] args) { Cat.Leg = 4; Cat.Run(30); Cat c = new Cat(); c.Eat(); }
?
3. 靜態(tài)構(gòu)造方法
靜態(tài)構(gòu)造函數(shù)用于初始化任何
class SimpleClass { // Static variable that must be initialized at run time. static readonly long baseline; // Static constructor is called at most one time, before any // instance constructor is invoked or member is accessed. static SimpleClass() { baseline = DateTime.Now.Ticks; } }
?
靜態(tài)構(gòu)造函數(shù)具有以下屬性:
-
靜態(tài)構(gòu)造函數(shù)不使用訪問修飾符或不具有參數(shù)。
-
類或結(jié)構(gòu)只能有一個(gè)靜態(tài)構(gòu)造函數(shù)。
-
靜態(tài)構(gòu)造函數(shù)不能繼承或重載。
-
靜態(tài)構(gòu)造函數(shù)不能直接調(diào)用,并且僅應(yīng)由公共語言運(yùn)行時(shí) (CLR) 調(diào)用。 可以自動(dòng)調(diào)用它們。
-
用戶無法控制在程序中執(zhí)行靜態(tài)構(gòu)造函數(shù)的時(shí)間。
-
自動(dòng)調(diào)用靜態(tài)構(gòu)造函數(shù)。 它在創(chuàng)建第一個(gè)實(shí)例或引用該類(不是其基類)中聲明的任何靜態(tài)成員之前初始化
-
如果未提供靜態(tài)構(gòu)造函數(shù)來初始化靜態(tài)字段,會(huì)將所有靜態(tài)字段初始化為其默認(rèn)值,如
-
如果靜態(tài)構(gòu)造函數(shù)引發(fā)異常,運(yùn)行時(shí)將不會(huì)再次調(diào)用該函數(shù),并且類型在應(yīng)用程序域的生存期內(nèi)將保持未初始化。 大多數(shù)情況下,當(dāng)靜態(tài)構(gòu)造函數(shù)無法實(shí)例化一個(gè)類型時(shí),或者當(dāng)靜態(tài)構(gòu)造函數(shù)中發(fā)生未經(jīng)處理的異常時(shí),將引發(fā)
-
靜態(tài)構(gòu)造函數(shù)的存在將防止添加
-
聲明為
static readonly
的字段可能僅被分配為其聲明的一部分或在靜態(tài)構(gòu)造函數(shù)中。 如果不需要顯式靜態(tài)構(gòu)造函數(shù),請(qǐng)?jiān)诼暶鲿r(shí)初始化靜態(tài)字段,而不是通過靜態(tài)構(gòu)造函數(shù),以實(shí)現(xiàn)更好的運(yùn)行時(shí)優(yōu)化。 -
運(yùn)行時(shí)在單個(gè)應(yīng)用程序域中多次調(diào)用靜態(tài)構(gòu)造函數(shù)。 該調(diào)用是基于特定類型的類在鎖定區(qū)域中進(jìn)行的。 靜態(tài)構(gòu)造函數(shù)的主體中不需要其他鎖定機(jī)制。 若要避免死鎖的風(fēng)險(xiǎn),請(qǐng)勿阻止靜態(tài)構(gòu)造函數(shù)和初始值設(shè)定項(xiàng)中的當(dāng)前線程。 例如,不要等待任務(wù)、線程、等待句柄或事件,不要獲取鎖定,也不要執(zhí)行阻止并行操作,如并行循環(huán)、
Parallel.Invoke
和并行 LINQ 查詢。
單例模式實(shí)現(xiàn)
class MyDbContext { private static MyDbContext _instance; // 禁止外部實(shí)例化 private MyDbContext() { } public static string DbName; public static string UserName; public static string Password; // 靜態(tài)構(gòu)造方法 static MyDbContext() { DbName = "SqlServer"; UserName = "sa"; Password = "123456"; // 實(shí)例化一次 _instance = new MyDbContext(); } // 對(duì)外提供訪問的路徑 public MyDbContext Instance { get { return _instance; } } public void Connection() { } public void Abort() { } }
?
4. 作業(yè)
-
定義一個(gè)靜態(tài)類
MyMath
-
在
MyMath
類中 實(shí)現(xiàn)兩個(gè)參數(shù)的方法:加,減,乘,除,平均數(shù) -
重載 :加,減,乘,除,平均數(shù)
-
定義一個(gè)非靜態(tài)類
CommonUtils
, 任意聲明兩個(gè)實(shí)例成員變量與靜態(tài)成員變量 -
在
CommonUtils
類中,聲明一個(gè)實(shí)例方法,并輸出 上述的實(shí)例成員變量與靜態(tài)成員變量。 -
在
CommonUtils
類中, 聲明一個(gè)靜態(tài)方法,并輸出靜態(tài)成員變量。
視頻教程:文章來源:http://www.zghlxwxcb.cn/news/detail-464463.html
C#入門到精通 - 網(wǎng)易云課堂 (163.com)文章來源地址http://www.zghlxwxcb.cn/news/detail-464463.html
到了這里,關(guān)于第十單元 面向?qū)ο蠖红o態(tài)類與靜態(tài)成員的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!