最近在看CLR via C#,複習一下,看著老是忘,做個筆記。 裝箱和拆箱 1.裝箱,值類型向引用類型轉換: 在托管堆中分配記憶體,分配的記憶體量是類型各欄位所需的記憶體量+類型對象指針所需的記憶體量+同步塊索引所需的記憶體量。 值類型的欄位複製到分配好的記憶體中 返回對象地址,現在對象地址是對象引用 2.拆箱 ...
最近在看CLR via C#,複習一下,看著老是忘,做個筆記。
裝箱和拆箱
1.裝箱,值類型向引用類型轉換:
在托管堆中分配記憶體,分配的記憶體量是類型各欄位所需的記憶體量+類型對象指針所需的記憶體量+同步塊索引所需的記憶體量。
值類型的欄位複製到分配好的記憶體中
返回對象地址,現在對象地址是對象引用
2.拆箱,引用類型向值類型轉換:
獲取已裝箱類型中的未裝箱部分,也就是對象的原始值的各個欄位
複製欄位的值從堆中到棧中的值類型實例中
所以拆箱是不需要分配記憶體的,但是都要複製。
== Equals的比較
引用類型進行比較,==比較兩個參數的引用地址。調用equlas的時候,如果該類型或基類(除了object)沒有重寫object.equlas方法,則調用object.equlas方法,比較兩個類型的引用地址,否則則調用該類型或基類重寫的equlas方法(比如string)。
值類型進行比較,==比較兩個參數的值。調用equlas的時候,因為值類型的基類System.ValueType重寫了equlas,使比較的時候比較的兩個參數的值,所以也會比較兩個參數的值。
object a = new Test { a = 1 };
object b = new Test { a = 1 };
Console.WriteLine(a == b); //false 因為比較的是引用的地址,兩個引用類型的對象引用地址自然不同
Console.WriteLine(a.Equals(b));//false 因為Test類沒有重寫equlas,則調用的是Object.equals,而Object的equlas比較的是引用的地址
object c = 1;
object d = 1;
Console.WriteLine(c==d);//false 兩個參數都已經裝箱,成為引用類型,所以引用地址不同
Console.WriteLine(c.Equals(d));//true,值類型的基類System.ValueType重寫了equlas,使比較的時候比較的兩個參數的值
object e = "123";
object f = "123";
Console.WriteLine(e==f); //true string類型做了優化,所以並沒有給f單獨分配記憶體,只是將已經分配好記憶體的"123"指向了f,所以引用地址相同
Console.WriteLine(e.Equals(f));//true System.String 重寫了equlas,使比較的時候比較的兩個參數的值(不過這裡因為引用地址相同,所以有沒有重寫都是返回true)
object l = string.Copy(e.ToString());
Console.WriteLine(l == e); //false 直接copy,另外分配記憶體複製值進去,就和普通引用對象一樣,所以引用地址不同
Console.WriteLine(l.Equals(e));//true System.String 重寫了equlas,使比較的時候比較的兩個參數的值,所以引用地址不同但值相同也返回true
int h = 1;
int i = 1;
Console.WriteLine(h==i); //true 值類型==比較的兩個數的值
Console.WriteLine(h.Equals(i));//true ,值類型的基類System.ValueType重寫了equlas,使比較的時候比較的兩個參數的值
總結:
最終,對於值類型,==和equlas都比較值。對於引用類型,==比較引用地址,如果沒重寫Object.equlas方法,比較地址,重寫了,則調用重寫的方法。
ReferenceEquals
object的靜態類型方法,比較兩個參數的引用地址。和==操作運算符很像,但是==是可以被重載的。所以比較引用類型的引用地址時候用這個最好。
Equlas的重寫
1.判斷傳遞的值是否為null,如果為null,則返回false
2.判斷傳遞的值和this是否引用同一地址,如果同一地址,則返回true
3.判斷傳遞的值的類型和this的類型是否一致,類型不一致,則不可能相等,返回false
4.根據傳遞的值的欄位和this的欄位進行比較,只要有不一致,則返回false
5.調用基類的equlas,如果為true,則返回true,如果為false,則返回false。