程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> [C#基礎知識系列]全面解析C#中靜態與非靜態

[C#基礎知識系列]全面解析C#中靜態與非靜態

編輯:C#入門知識

一、引言

  在C#中,靜態和非靜態的特征對於我們來說是再熟悉不過了,但是很少看到有一篇文章去好好地總結靜態和非靜態它們之間的不同,為了幫助大家更好地去理解靜態和非靜態特征, 所以將在這篇文章中幫大家全面總結下它們之間的不同,包括靜態類,靜態成員和靜態構造函數。希望在大家鞏固基礎的時候可以拿出來好好復習下的。下面廢話不多了,直接進入我們今天的主題。

二、為什麼需要靜態特征

  在自定義類或看.NET Framework類庫中都可以發現,類中大部分都是具體實例特征(也就是沒有static標識的),同時我們也能看到一些具有靜態特征的類或成員,例如我們經常使用的Console類以及WriteLine方法就是靜態的。然而有些朋友會疑惑,為什麼還要有靜態特征的呢?干脆都定義為實例的好了? 然後靜態特征的存在肯定有它存在的原因的,並不是我們就是要這麼定義的,其實我們創建出來的學生他們都有一些共有的特征,如同一個班級,學校等, 如果我們把班級、學校這樣的特征也定義為實例的話,那麼我們不是每次創建對象實例的時候都為這些共有的特征分配一次內存的,這樣不僅對內存空間的浪費也是不滿足生活常識的,此時我們就可以把班級、學校這樣的特征定義為靜態特征,這樣所有實例都可以共享這兩個特征,並且不需要為每個對象實例分配內存。

三、比較靜態特征和非靜態特征

3.1 靜態類與非靜態類

  • 靜態類和非靜態類在C#中定義基本是一樣的,只是靜態類定義需要加上static修飾符而已。下面就直接總結下它們之間的區別:
  • 靜態類只能包含靜態成員,否則會拋出編譯錯誤;然而非靜態類既可以包含非靜態成員也可以包含靜態成員
  • 靜態類是不能實例化,之所以不能實例化,是因為靜態類會導致C#編譯器將該類同時標記為abstract和sealed,並且編譯器不會在類型中生成一個實例的構造函數,從而導致靜態類不能實例化,具體原因可以見下圖;非靜態類可以,並且靜態成員的訪問只能通過類來進行訪問,因為靜態成員是屬於類的。
     

上面代碼用IL反匯編程序得到的IL代碼結構為:

 

3.2 靜態構造函數與實例構造函數

  • 靜態構造函數用來初始化類中的靜態成員的,包括靜態字段和靜態屬性,並且靜態構造函數是不能帶有參數、不能有訪問修飾符,靜態構造函數的調用是由CLR第一次調用類成員之前執行的。
  • 下面還是直接總結下靜態構造函數與實例構造函數之間的區別:
  • 靜態構造函數可以與無參的實例構造函數同時存在
  • 靜態構造函數在CLR加載類時執行,然而實例構造函數在每次實例創建時都會執行
  • 靜態構造函數只能對靜態成員初始化,不能對非靜態成員進行初始化操作,然而實例構造函數,既可以初始化實例成員也可以初始化靜態成員,但靜態只讀字段除外
  • 靜態構造函數只被執行一次,但是CLR也不能確定它什麼時候被執行,它的執行方式有兩種,precise和before-field-init,這個會在下一篇文章中詳細給大家介紹,這裡先提出給大家一個思考的空間。而實例構造函數在每次創建對象實例時都會被執行,創建幾個就會執行幾次
  • 一個類只能有一個靜態構造函數,卻可以有多個實例構造函數

靜態字段的初始值在靜態構造函數調用之前被指定,構造函數的執行順序大致如下圖所示:

3.3 靜態字段、屬性和實例字段、屬性

下面就直接總結下它們之間的區別:

  • 靜態成員包括靜態屬性和靜態字段,靜態字段一般實現為private,靜態屬性一般實現為public,從而來體現類的封裝性
  • 靜態成員和類相關聯,不依賴於對象而存在,只能由類來訪問;實例成員與具體類相關聯,只能由對象實例訪問
  • 靜態成員不管創建多少實例對象,都在內存中只有一份,實例成員每創建一個實例對象,都會在內存中分配一塊內存區域。

3.4 靜態方法與實例方法

類似於靜態字段和屬性,靜態方法共享代碼段,同樣以static關鍵字來標識靜態方法,對於他們之間的區別總結為:

  • 靜態方法只能訪問靜態成員和方法,但是可以間接通過創建實例對象來訪問實例字段、屬性和方法;實例方法既可以訪問實例成員也可以訪問靜態成員
  • 靜態方法由類方法‘實例方法由對象訪問
  • 靜態方法不能引用this關鍵字,而實例方法可以
  • 靜態方法不能被標識為virtual、abstract或override,靜態方法可以被派生訪問,但是不能被派生類重寫
  • Main方法為靜態的,所以Main方法不能直接訪問類中的實例字段、屬性和方法,否則編譯器會報錯
  • 靜態方法一般用於作為通用的工具類來實現
  • 在性能上,靜態方法和實例方法的差別不大。因為,它們都是在JIT加載類的時候分配內存的,不同的是靜態方法是以類為引用,而實例方法是以對象為引用,創建實例時,不會再為靜態方法分配內存,所有實例對象共用一個類的方法代碼,所以,靜態方法和實例方法的調用,區別僅在於靜態方法可以直接調用,而實例方法需要當前對象指針指向該方法,在性能上差不並不大。

四、小結

  到這裡,本文章的內容就介紹完了,通過對靜態特征和非靜態特征的由來來揭開一些都是源於生活的觀點,然後再詳細分析了靜態特征與非靜態特征在C#語言中的區別,希望這些總結可以幫助大家在復習基礎知識的時候可以有用。同時也是自己的一個復習筆記的。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved