第十七节:易混淆的概念(静态和非静态、拆箱和装箱)
一. 靜態(tài)和非靜態(tài)
1. 概念介紹
① 靜態(tài)類(被static修飾) vs? 普通類(沒有被static修飾)
② 靜態(tài)成員:被static修飾的成員,比如:靜態(tài)方法、靜態(tài)字段等
③ 普通成員(實(shí)例成員):不被static修飾的成員,比如:普通方法、普通字段
2. 運(yùn)行機(jī)制
① 靜態(tài)成員在程序運(yùn)行的時(shí)候會“先于”實(shí)例成員被加載到內(nèi)存中,靜態(tài)成員不需要單獨(dú)創(chuàng)建,當(dāng)然靜態(tài)類也不能被實(shí)例化。
比如:靜態(tài)字段和靜態(tài)構(gòu)造函數(shù)只有在程序第一次使用該類之前被調(diào)用,而且只能調(diào)用一次,利用該特性,可以設(shè)計(jì)單例模式。
補(bǔ)充單例模式的代碼:
?View Code
public class STwo
? ? {
? ? ? ? /// <summary>
? ? ? ? /// 模擬耗時(shí)的構(gòu)造函數(shù)
? ? ? ? /// </summary>
? ? ? ? private STwo()
? ? ? ? {
? ? ? ? ? ? long result = 0;
? ? ? ? ? ? for (int i = 0; i < 1000000; i++)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? result += i;
? ? ? ? ? ? }
? ? ? ? ? ? Thread.Sleep(1000);
? ? ? ? ? ? Console.WriteLine("{0}被構(gòu)造...", this.GetType().Name);
? ? ? ? }
? ? ? ? private static STwo _STwo = null;
? ? ? ? /// <summary>
? ? ? ? /// 靜態(tài)的構(gòu)造函數(shù):只能有一個(gè),且是無參數(shù)的
? ? ? ? /// 由CLR保證,只有在程序第一次使用該類之前被調(diào)用,而且只能調(diào)用一次
? ? ? ? /// </summary>
? ? ? ? static STwo()
? ? ? ? {
? ? ? ? ? ? _STwo = new STwo();
? ? ? ? }
? ? ? ? public static STwo CreateIntance()
? ? ? ? {
? ? ? ? ? ? return _STwo;
? ? ? ? }
? ? }
?View Code
public ?class SThird
? ? {
? ? ? ? /// <summary>
? ? ? ? /// 模擬耗時(shí)的構(gòu)造函數(shù)
? ? ? ? /// </summary>
? ? ? ? private SThird()
? ? ? ? {
? ? ? ? ? ? long result = 0;
? ? ? ? ? ? for (int i = 0; i < 1000000; i++)
? ? ? ? ? ? {
? ? ? ? ? ? ? ? result += i;
? ? ? ? ? ? }
? ? ? ? ? ? Thread.Sleep(1000);
? ? ? ? ? ? Console.WriteLine("{0}被構(gòu)造...", this.GetType().Name);
? ? ? ? }
? ? ? ? /// <summary>
? ? ? ? /// 靜態(tài)變量:由CLR保證,在程序第一次使用該類之前被調(diào)用,而且只調(diào)用一次
? ? ? ? /// </summary>
? ? ? ? private static SThird _SThird = new SThird();
? ? ? ? public static SThird CreateIntance()
? ? ? ? {
? ? ? ? ? ? return _SThird;
? ? ? ? }
? ? }
② 實(shí)例成員:只有創(chuàng)建了對象(即進(jìn)行了類的實(shí)例化)才會存在于內(nèi)存中。
證明:在StaticInstroduceDemo類中的靜態(tài)變量a上加斷點(diǎn)(方法體內(nèi)部加斷點(diǎn),兩次實(shí)例化類的時(shí)候加斷點(diǎn)),然后在客戶端實(shí)例化兩次 StaticInstroduceDemo類,分別調(diào)用ShowStaticInstroduce方法,
發(fā)現(xiàn):第一次實(shí)例化的時(shí)候進(jìn)入靜態(tài)變量a上的斷點(diǎn),然后在調(diào)用對應(yīng)的方法,而第二次實(shí)例化的時(shí)候不再進(jìn)入靜態(tài)變量a上的斷點(diǎn),直接進(jìn)入調(diào)用的方法。從而驗(yàn)證了:靜態(tài)成員優(yōu)先于實(shí)例成員進(jìn)入內(nèi)存,且只在第一次使用該類的時(shí)候進(jìn)行初始化分配內(nèi)存,后續(xù)將不在分配.
3. 基于以上運(yùn)行機(jī)制可以得出以下幾個(gè)結(jié)論
① 普通類:
a. 普通類中可以存在靜態(tài)成員(靜態(tài)方法、靜態(tài)字段),但里面的靜態(tài)方法不能調(diào)用普通類中的普通字段<普通類沒有實(shí)例化的話,普通字段是不存在的>。
b. 普通類中普通方法可以調(diào)用里面的靜態(tài)字段<靜態(tài)成員先于實(shí)例成員加載到內(nèi)存中>
eg:
② 靜態(tài)類:
靜態(tài)類中只能存在靜態(tài)成員(靜態(tài)方法和靜態(tài)字段)
4. 調(diào)用形式
① 靜態(tài)成員: 類名.靜態(tài)成員名
② 實(shí)例成員: 實(shí)例名.實(shí)例成員名
5. 聲明周期
① 對于C/S程序:每啟動一次,相當(dāng)于一次生命周期,關(guān)閉程序生命周期結(jié)束,多次打開客戶端程序互不干擾。?
驗(yàn)證:上述的ShowStaticInstroduce方法,兩次實(shí)例化后調(diào)用輸出的結(jié)果是2,3 。此時(shí)我再打開一個(gè)客戶端,結(jié)果依舊是2,3,這也很好證明了聲明周期的問題。
② 對于B/S程序:static修飾的成員存儲在服務(wù)器端中,與客戶端關(guān)閉與否無關(guān)。《詳見HomeController下的TestStatic方法》
驗(yàn)證:打開不同瀏覽器,分別調(diào)用TestStatic1方法,發(fā)現(xiàn)每點(diǎn)擊一次按鈕,返回值增加1,關(guān)閉該瀏覽器,重新點(diǎn)擊,返回值在原基礎(chǔ)上加1.?關(guān)閉IIS重新運(yùn)行,返回值重新計(jì)數(shù)。證明:在B/S模式下,static修飾的成員存儲在服務(wù)器端內(nèi)存中,與客戶端關(guān)閉與否無關(guān)。
?
6. 使用場景
① 對于C/S程序:static修飾的變量可以當(dāng)作緩存來使用。
② 對于B/S程序:可以利用static的特性來設(shè)計(jì)單例模式,或者面向多線程存儲數(shù)據(jù),進(jìn)行資源的共享<PS: 不考慮性能方面問題和一些極端情況>。
③ 作為工具類,全局資源共享。
二. 拆箱和裝箱
1. 補(bǔ)充兩個(gè)概念:
值類型:int、double、char、bool、decimal、struct、enum
引用類型:各種class類、string、數(shù)組、接口、委托、object
2. 裝箱:
將值類型→引用類型
3. 拆箱:
將引用類型→值類型
4. 經(jīng)典面試題
請問下面代碼涉及到幾次拆箱和裝箱。
分析:
① 第一次裝箱發(fā)生在 object m2 = m1;
② 第一次拆箱發(fā)生在 (int)m2 上;
所以很多人認(rèn)為答案是:1次裝箱和1次拆箱,顯然是不對的。
我們繼續(xù)分析,熟悉 Console.WriteLine原理的知道內(nèi)部調(diào)用string.Concat()方法進(jìn)行拼接,而Contact有很多重載,F12看源碼可知,
該案例只能使用 public static String Concat(object arg0, object arg1); 這個(gè)重載,
所以第2次裝箱和第3次裝箱發(fā)生在 m1→object 和(int)m2→object上。
所以最終答案是 1次拆箱和3次裝箱
5.? 特別注意:用什么類型進(jìn)行裝箱的,拆箱就拆成什么類型,否則會拋異常,無法進(jìn)行類型轉(zhuǎn)換。
?
?
?PS:如果你對.Net其他知識感興趣,可以參考??DotNet進(jìn)階系列(持續(xù)更新)??ASP.NET MVC深入淺出系列(持續(xù)更新)?ORM系列之Entity FrameWork詳解(持續(xù)更新)? ??
? ? ? ?那些年我們一起追逐的多線程(Thread、ThreadPool、委托異步調(diào)用、Task/TaskFactory、Parallerl、async和await)
總結(jié)
以上是生活随笔為你收集整理的第十七节:易混淆的概念(静态和非静态、拆箱和装箱)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 怎么用手机支付宝还信用卡
- 下一篇: 大额现金管理正式开始试点,存取钱超过一个