您好,登錄后才能下訂單哦!
在C#中,靜態(tài)和非靜態(tài)的特征對于我們來說是再熟悉不過了,但是很少看到有一篇文章去好好地總結(jié)靜態(tài)和非靜態(tài)它們之間的不同,為了幫助大家更好地去理解靜態(tài)和非靜態(tài)特征, 所以將在這篇文章中幫大家全面總結(jié)下它們之間的不同,包括靜態(tài)類,靜態(tài)成員和靜態(tài)構(gòu)造函數(shù)。希望在大家鞏固基礎(chǔ)的時候可以拿出來好好復(fù)習下的。下面廢話不多了,直接進入我們今天的主題。
在自定義類或看.NET Framework類庫中都可以發(fā)現(xiàn),類中大部分都是具體實例特征(也就是沒有static標識的),同時我們也能看到一些具有靜態(tài)特征的類或成員,例如我們經(jīng)常使用的Console類以及WriteLine方法就是靜態(tài)的。然而有些朋友會疑惑,為什么還要有靜態(tài)特征的呢?干脆都定義為實例的好了? 然后靜態(tài)特征的存在肯定有它存在的原因的,并不是我們就是要這么定義的,其實我一直認為不管是什么都是源于生活的, 技術(shù)的實現(xiàn)也是一樣,比如我們開發(fā)程序,需要掌握技術(shù)外,其實更重要的是業(yè)務(wù)邏輯這塊的,如果你都不知道你開發(fā)的東西是怎樣的一個流程,即使你技術(shù)再牛做出來的東西都是反人類的東西(也就是指不符合用戶的用戶習慣和之前的一個業(yè)務(wù)需求),其實靜態(tài)特征的存在也是源于生活的,對于類好比就是我們現(xiàn)實生活中的人或事物,靜態(tài)特征和非靜態(tài)特征就好比生活中人或事物具有的特征, 我們詢問人的時候或者電視劇警察查案件的時候,都會聽到這樣一句話 "那個人有什么特征?"或 “嫌疑犯有什么特征?多高,年齡等” 其實高度、年齡、性別都是一個人的特征,所以這些在語言范疇就需要為其進行定義了,也就是我們定義的實例成員了,然而有些特征需要被所有對象實例所共有的,這些特征在語言范疇就定義為靜態(tài)特征,具體哪些特征可以定義為靜態(tài)特征呢? 其實這點一樣是源于生活的,所以我們在開發(fā)軟件的過程中,必不可少的一個流程就是需求分析了,只有在了解客戶需求的條件下才能進行之后的所有流程的, 例如一個班級有很多學生,每個學生是一個實體,在語言范疇就可以定義一個類,當我們需要一個學生的時候就可以通過new 關(guān)鍵字創(chuàng)建一個出來(說到這里又讓我想到了惡搞泰囧的圖片——你有對象嗎?沒對象,你們程序員可以自己new一個啊?),然而我們創(chuàng)建出來的學生他們都有一些共有的特征,如同一個班級,學校等, 如果我們把班級、學校這樣的特征也定義為實例的話,那么我們不是每次創(chuàng)建對象實例的時候都為這些共有的特征分配一次內(nèi)存的,這樣不僅對內(nèi)存空間的浪費也是不滿足生活常識的,此時我們就可以把班級、學校這樣的特征定義為靜態(tài)特征,這樣所有實例都可以共享這兩個特征,并且不需要為每個對象實例分配內(nèi)存。
靜態(tài)類和非靜態(tài)類在C#中定義基本是一樣的,只是靜態(tài)類定義需要加上static修飾符而已。下面就直接總結(jié)下它們之間的區(qū)別:
靜態(tài)類只能包含靜態(tài)成員,否則會拋出編譯錯誤;然而非靜態(tài)類既可以包含非靜態(tài)成員也可以包含靜態(tài)成員
靜態(tài)類是不能實例化,之所以不能實例化,是因為靜態(tài)類會導(dǎo)致C#編譯器將該類同時標記為abstract和sealed,并且編譯器不會在類型中生成一個實例的構(gòu)造函數(shù),從而導(dǎo)致靜態(tài)類不能實例化,具體原因可以見下圖;非靜態(tài)類可以,并且靜態(tài)成員的訪問只能通過類來進行訪問,因為靜態(tài)成員是屬于類的。
publicstaticclass StaticClass { privatestaticstring name; }
上面代碼用IL反匯編程序得到的IL代碼結(jié)構(gòu)為:
靜態(tài)構(gòu)造函數(shù)用來初始化類中的靜態(tài)成員的,包括靜態(tài)字段和靜態(tài)屬性,并且靜態(tài)構(gòu)造函數(shù)是不能帶有參數(shù)、不能有訪問修飾符,靜態(tài)構(gòu)造函數(shù)的調(diào)用是由CLR第一次調(diào)用類成員之前執(zhí)行的。
下面還是直接總結(jié)下靜態(tài)構(gòu)造函數(shù)與實例構(gòu)造函數(shù)之間的區(qū)別:
靜態(tài)構(gòu)造函數(shù)可以與無參的實例構(gòu)造函數(shù)同時存在
靜態(tài)構(gòu)造函數(shù)在CLR加載類時執(zhí)行,然而實例構(gòu)造函數(shù)在每次實例創(chuàng)建時都會執(zhí)行
靜態(tài)構(gòu)造函數(shù)只能對靜態(tài)成員初始化,不能對非靜態(tài)成員進行初始化操作,然而實例構(gòu)造函數(shù),既可以初始化實例成員也可以初始化靜態(tài)成員,但靜態(tài)只讀字段除外
靜態(tài)構(gòu)造函數(shù)只被執(zhí)行一次,但是CLR也不能確定它什么時候被執(zhí)行,它的執(zhí)行方式有兩種,precise和before-field-init,這個會在下一篇文章中詳細給大家介紹,這里先提出給大家一個思考的空間。而實例構(gòu)造函數(shù)在每次創(chuàng)建對象實例時都會被執(zhí)行,創(chuàng)建幾個就會執(zhí)行幾次
一個類只能有一個靜態(tài)構(gòu)造函數(shù),卻可以有多個實例構(gòu)造函數(shù)
靜態(tài)字段的初始值在靜態(tài)構(gòu)造函數(shù)調(diào)用之前被指定,構(gòu)造函數(shù)的執(zhí)行順序大致如下圖所示:
下面就直接總結(jié)下它們之間的區(qū)別:
靜態(tài)成員包括靜態(tài)字段和靜態(tài)字段,靜態(tài)字段一般實現(xiàn)為private,靜態(tài)屬性一般實現(xiàn)為public,從而來體現(xiàn)類的封裝性
靜態(tài)成員和類相關(guān)聯(lián),不依賴于對象而存在,只能由類來訪問;實例成員與具體類相關(guān)聯(lián),只能由對象實例訪問
靜態(tài)成員不管創(chuàng)建多少實例對象,都在內(nèi)存中只有一份,實例成員每創(chuàng)建一個實例對象,都會在內(nèi)存中分配一塊內(nèi)存區(qū)域。
類似于靜態(tài)字段和屬性,靜態(tài)方法共享代碼段,同樣以static關(guān)鍵字來標識靜態(tài)方法,對于他們之間的區(qū)別總結(jié)為:
靜態(tài)方法只能訪問靜態(tài)成員和方法,但是可以間接通過創(chuàng)建實例對象來訪問實例字段、屬性和方法;實例方法既可以訪問實例成員也可以訪問靜態(tài)成員
靜態(tài)方法由類方法‘實例方法由對象訪問
靜態(tài)方法不能引用this關(guān)鍵字,而實例方法可以
靜態(tài)方法不能被標識為virtual、abstract或override,靜態(tài)方法可以被派生訪問,但是不能被派生類重寫
Main方法為靜態(tài)的,所以Main方法不能直接訪問類中的實例字段、屬性和方法,否則編譯器會報錯
靜態(tài)方法一般用于作為通用的工具類來實現(xiàn)
在性能上,靜態(tài)方法和實例方法的差別不大。因為,它們都是在JIT加載類的時候分配內(nèi)存的,不同的是靜態(tài)方法是以類為引用,而實例方法是以對象為引用,創(chuàng)建實例時,不會再為靜態(tài)方法分配內(nèi)存,所有實例對象共用一個類的方法代碼,所以,靜態(tài)方法和實例方法的調(diào)用,區(qū)別僅在于靜態(tài)方法可以直接調(diào)用,而實例方法需要當前對象指針指向該方法,在性能上差不并不大。
到這里,本文章的內(nèi)容就介紹完了,通過對靜態(tài)特征和非靜態(tài)特征的由來來揭開一些都是源于生活的觀點,然后再詳細分析了靜態(tài)特征與非靜態(tài)特征在C#語言中的區(qū)別,希望這些總結(jié)可以幫助大家在復(fù)習基礎(chǔ)知識的時候可以有用。同時也是自己的一個復(fù)習筆記的。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。