欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#中的引用類型以及特殊引用類型詳解

 更新時(shí)間:2022年07月31日 09:43:17   作者:Darren?Ji  
本文詳細(xì)講解了C#中的引用類型以及特殊引用類型,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

基本

哪些屬于引用類型

類(object,string),接口、數(shù)組、委托

引用類型分配在哪里

  • 引用類型變量位于線程棧。
  • 引用類型實(shí)例分配在托管堆上。
  • 當(dāng)引用類型實(shí)例的大小小于85000bytes,被分配在GC堆上,當(dāng)大于或等于85000bytes,被分配在LOH(Large Object Heap)上。

變量(Variable),對(duì)象(Object),實(shí)例(Instance)

變量:
變量分配在線程棧上。
變量可以是值類型,也可以是引用類型。
當(dāng)變量是引用類型時(shí),包含了對(duì)對(duì)象的引用(內(nèi)存地址),也叫做"對(duì)象引用"。

對(duì)象:
對(duì)類、接口、委托和數(shù)組等的一個(gè)抽象描述。

實(shí)例:
在堆上創(chuàng)建的對(duì)象,稱為對(duì)象實(shí)例。

引用類型沒有new意味著什么?

Object a = null;
Console.WriteLine(a.ToString());
運(yùn)行報(bào)錯(cuò)"未將對(duì)象引用設(shè)置到對(duì)象實(shí)例"。
意思是,在線程棧上創(chuàng)建的變量a沒有指向到堆上的對(duì)象實(shí)例。

托管堆上的垃圾回收

GC會(huì)遍歷所有托管堆上的對(duì)象,按照一定的遞歸遍歷算法,對(duì)那些沒有被引用的不可訪問對(duì)象實(shí)施回收。

new的背后發(fā)生了什么

    class Program 
    { 
        static void Main(string[] args) 
        { 
            Person p; 
            p = new Person(20); 
        } 
    }

    public class Person 
    { 
        public int _age;

        public Person(int age) 
        { 
            _age = age; 
        }

        public Person() 
        { 
            
        } 
    }

另外,引用類型的值,比如這里的引用類型Person中的值_age也被分配在托管堆上。   

線程棧上的2個(gè)變量引用同一個(gè)對(duì)象實(shí)例的內(nèi)存地址

線程棧上的2個(gè)變量引用同一個(gè)對(duì)象實(shí)例的內(nèi)存地址,改變其中一個(gè)變量的值會(huì)影響到另外一個(gè)變量。

    class Program 
    { 
        static void Main(string[] args) 
        { 
            Person p1 = new Person(20); 
            Person p2 = p1; 
            Console.WriteLine("沒有改變時(shí)p2的年齡是:" + p2._age + "歲"); 
            p1._age = 18; 
            Console.WriteLine("改變p1的值,p2的年齡也被改變了,現(xiàn)在是:" + p2._age + "歲,真好,年輕了!"); 
            Console.ReadKey(); 
        } 
    }

    public class Person 
    { 
        public int _age;

        public Person(int age) 
        { 
            _age = age; 
        }

        public Person() 
        { 
            
        } 
    }

string類型是特殊的引用類型

特殊性體現(xiàn)在

從應(yīng)用角度體現(xiàn)了值類型語義,從內(nèi)存角度實(shí)現(xiàn)為引用類型存儲(chǔ),位于托管堆。

什么是string

可以看作是char的集合char[]    

string創(chuàng)建與實(shí)例化

string str = "Hello";

以下錯(cuò)誤
String str = new String("Hello");
因?yàn)镾ystem.String沒有提供此構(gòu)造函數(shù)

以下可以
Char[] cs = {'a', 'b','c'};
String strArr = new String(cs);
但很少使用這種方式。

字符串的恒定性Immutability

是指字符串一經(jīng)創(chuàng)建,就不可改變。
字符串一旦創(chuàng)建,在托管堆上分配一塊連續(xù)的內(nèi)存空間。

恒定性的好處:
對(duì)String對(duì)象的任意操作,不會(huì)改變?cè)址?br />操作字符串不會(huì)出現(xiàn)線程同步的問題。
成就了字符串駐留。

恒定性的不足:
因?yàn)楹愣ㄐ裕瑢?duì)字符串的任何操作,比如字符串比較,字符串鏈接,字符串格式化等都會(huì)創(chuàng)建新的字符串,這樣造成內(nèi)存與性能的雙重?fù)p耗。如下:

public static void Main() 
{ 
    string str = "This is a test about immuntablility of string type."; 
    Console.WriteLine(str.Inseert(0,"Hi").Substring(19).ToUpper()); 
    Console.WriteLine(str); 
}

由于Insert,Substring,ToUpper這些方法,都會(huì)創(chuàng)建出新的臨時(shí)字符串,而這些新的字符串不被其他代碼引用的時(shí)候,就會(huì)被垃圾回收,造成性能上的損失。

恒定性的前提,String為密封類:

public sealed class String:IComparable, ICloneable,IConvertible,IComparable<string>,IEnumerable<char>,IEnumerable,IEquatable<string>

字符串駐留String Interning

MSDN對(duì)于字符駐留的定義:公共語言運(yùn)行庫通過維護(hù)一個(gè)哈希表(Hash Table)來存放字符串,該表成為拘留池,也叫駐留池。

字符串駐留彌補(bǔ)了恒定性的不足:
對(duì)于相同的字符串,CLR不會(huì)不會(huì)為其分配內(nèi)存空間,而是共享同一內(nèi)存。
CLR內(nèi)部維護(hù)了一個(gè)哈希表HashTable來管理其創(chuàng)建的大部分String對(duì)象。key是string本身,value是string對(duì)應(yīng)的內(nèi)存地址。

駐留的2個(gè)靜態(tài)方法:
public static string Intern(string str);
當(dāng)str位于作為key位于CLR的駐留池時(shí),返回對(duì)str的引用,否則將str字符串添加到hash table中,作為key,并返回引用。

public static string IsInterned(string str);
當(dāng)str位于作為key位于CLR的駐留池時(shí),返回對(duì)str的引用,否則返回null引用,也不添加到hash table中。

字符串駐留是進(jìn)程級(jí)的

可以跨應(yīng)用程序域AppDomain而存在,駐留池在CLR加載時(shí)創(chuàng)建,分配在System Domain中,被進(jìn)程所有AppDomain所共享,其生命周期不受GC控制。

例子1:

        static void Main(string[] args) 
        { 
            string strA = "ab"; 
            string strB = "ab"; 
            Console.WriteLine(ReferenceEquals(strA,strB)); 
            string strC = "a"; 
            string strD = strC + "b"; 
            Console.WriteLine(ReferenceEquals(strA, strD)); 
            strD = String.Intern(strD); 
            Console.WriteLine(ReferenceEquals(strA,strD)); 
            Console.ReadKey(); 
        }

返回:

true
false
true

分析:

  • strA與strB內(nèi)容相同,在hash table中的key相同,對(duì)應(yīng)了一樣的引用地址,所以返回true。
  • strD的內(nèi)容雖然與strA相同,但由于是動(dòng)態(tài)生成的,不會(huì)把hash table中key為ab的引用地址賦值給strD,所以strA與strD引用地址不一樣,返回false。
  • strD = String.Intern(strD);手動(dòng)對(duì)strD實(shí)施駐留,并發(fā)現(xiàn)hash table中已經(jīng)有了ab這個(gè)key,就把對(duì)應(yīng)的引用地址賦值給了strD,這樣,strA與strD引用地址相同,返回true。

例子2:

        static void Main(string[] args) 
        { 
            string s1 = "abc"; 
            string s2 = "ab"; 
            string s3 = s2 + "c"; 
            Console.WriteLine(string.IsInterned(s3) ?? "null"); 
            Console.WriteLine(ReferenceEquals(s1,s3)); 
            Console.ReadKey(); 
        }

返回:

abc
false   

分析:

  • string.IsInterned(s3)對(duì)s3進(jìn)行手動(dòng)駐留,發(fā)現(xiàn)hash table中abc這個(gè)key,于是,就返回abc的引用地址。但并沒有把引用地址賦值給s3。
  • s1和s3的引用地址還是不一樣,返回false。

例子3:

        static void Main(string[] args) 
        { 
            string strA = "abcdef"; 
            string strC = "abc"; 
            string strD = strC + "def"; 
            Console.WriteLine(ReferenceEquals(strA,strD)); 
            string StrE = "abc" + "def"; 
            Console.WriteLine(ReferenceEquals(strA,StrE)); 
            Console.ReadKey(); 
        }

返回:

False,       
true

分析:

  • 因?yàn)閟trD = strC + "def"中strD的內(nèi)容雖然與strA想同,但因?yàn)槭莿?dòng)態(tài)生成的,不會(huì)被添加到hash table中,所以引用地址不一樣,返回false。
  • "abc"+"def在IL中呈現(xiàn)為abcdef,不是動(dòng)態(tài)生成的,并且發(fā)現(xiàn)hash table中已經(jīng)有了abcdef這個(gè)key,于是就把對(duì)應(yīng)的引用地址賦值給了strE,這樣strA和StrE就有了相同的引用地址,返回true。如圖:

例子4:

        static void Main(string[] args) 
        { 
            string s = "abc"; 
            //IsInterned()獲取字符串變量的引用 
            Console.WriteLine(string.IsInterned(s) ?? "null"); 
            Console.ReadKey(); 
        }

返回

"abc"。

分析:通過string s = "abc"使得hash table中有abc這個(gè)key,當(dāng)進(jìn)行string.IsInterned(s)手動(dòng)駐留判斷的時(shí)候,發(fā)現(xiàn)有abc這個(gè)key,就把對(duì)應(yīng)的引用地址返回。

例子5:

    class Program 
    { 
        static void Main(string[] args) 
        { 
            string s = "ab"; 
            s += "c"; 
            //IsInterned()獲取字符串變量的引用 
            Console.WriteLine(string.IsInterned(s) ?? "null"); 
            Console.ReadKey(); 
        } 
    }

返回

null

分析:通過string s = "ab";使得hash table中有了ab這個(gè)key,s += "c"是動(dòng)態(tài)拼接,不會(huì)把a(bǔ)bc放到hashtable中,所以當(dāng)通過string.IsInterned(s)手動(dòng)駐留判斷的時(shí)候,發(fā)現(xiàn)沒有abc這個(gè)key,就返回null。

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請(qǐng)查看下面相關(guān)鏈接

相關(guān)文章

  • c#實(shí)現(xiàn)多線程局域網(wǎng)聊天系統(tǒng)

    c#實(shí)現(xiàn)多線程局域網(wǎng)聊天系統(tǒng)

    這篇文章主要介紹了c#實(shí)現(xiàn)多線程局域網(wǎng)聊天系統(tǒng)的相關(guān)代碼,有此方面需求的小伙伴可以參考下。
    2015-06-06
  • 最新評(píng)論