物件導向三大特性:封裝,繼承,多態。那麼類是從哪裡繼承呢?在物件導向語言中有基類或者也叫做超類的概念,也就是所有類都是從這個類繼承得來的,這個超類叫Object。.net中是這樣描述Object類的:
支援 .NET Framework 類階層中的所有類,並為衍生類別提供低層級服務。這是 .NET Framework 中所有類的最終基類;它是類型階層的根。
既然是超類,Object定義了一些關鍵的方法。如下:
Equals方法——用於比較兩個執行個體是否相等。
public virtual bool Equals(Object obj),比較當前執行個體是否與obj相等;
public static bool Equals(Object objA,Object objB),比較指定兩個執行個體是否相等。
Finalize 方法——允許 Object 在“記憶體回收”回收 Object 之前嘗試釋放資源並執行其他清理操作。
GetHashCode 方法——擷取一個對象的Hash值。
GetType方法——擷取當前執行個體的Type。
MemberwiseClone 方法——建立當前執行個體的淺表副本,也就是如果當前執行個體有值,新建立的執行個體中只擷取實值型別的值,參考型別是沒有擷取值。
ReferenceEquals 方法——比較兩個執行個體是否相同,與static bool Equals(Object objA,Object objB)用法一樣。
ToString 方法——這個平時用的比較多,用於返回當前執行個體的string。
Object是超類,所以C#中的所有類都具有這些方法。
下面著重介紹下Equals和ToString方法。
一、對象比較
C#中有實值型別和參考型別,簡單的理解就是實值型別儲存對象的值,而參考型別是執行個體的引用,類似於C語言的指標。因此在使用對象的比較的時候,實值型別比較兩個對象值是否相等,參考型別比較指定的引用是否引用同一個對象。當然有時也會比較參考型別指向的執行個體值是否相同。
下面是對象比較的代碼:
using System;using System.Collections.Generic;using System.Text;namespace YYS.CSharpStudy.MainConsole.AboutObject{ public class Int32Value : ICloneable { //欄位,定義欄位最好賦上初值 private int intValue = 0; /// <summary> /// 屬性 /// </summary> public int IntValue { get { return this.intValue; } set { this.intValue = value; } } /// <summary> /// 定義一個無參構造器 /// </summary> public Int32Value() { } /// <summary> /// 帶參數的構造器 /// </summary> public Int32Value(int value) { this.intValue = value; } ///// <summary> ///// 實現ICloneable介面 ///// </summary> public object Clone() { return this.MemberwiseClone(); } }}
調用:
using System;using YYS.CSharpStudy.MainConsole.AboutObject;namespace YYS.CSharpStudy.MainConsole{ class Program { static void Main(string[] args) { //聲明一個Int32Value類型的引用value1,指向一個執行個體 Int32Value value1 = new Int32Value(30); //聲明value2,指向value1,此時兩個引用是指向一個執行個體的 Int32Value value2 = value1; //使用==比較 Console.WriteLine(string.Format("value1和value2 {0}", value1 == value2 ? "相同" : "不相同"));//相同 //調用Clone,複製一個value1的副本,賦值給value2 //此時是兩個執行個體了 value2 = (Int32Value)value1.Clone(); //使用==比較 Console.WriteLine(string.Format("value1和value2 {0}", value1 == value2 ? "相同" : "不相同"));//不相同 //將value1賦給value2,此時他們指向同一個執行個體 value2 = value1; //使用Equals比較 Console.WriteLine(string.Format("value1和value2 {0}", value1.Equals(value2) ? "相同" : "不相同"));//相同 //調用Clone,複製一個value1的副本,賦值給value2 //此時是兩個執行個體了 value2 = (Int32Value)value1.Clone(); //使用Equals比較 Console.WriteLine(string.Format("value1和value2 {0}", value1.Equals(value2) ? "相同" : "不相同"));//不相同 Console.ReadLine(); } }}
結果:
由代碼可以看出:
a、對於參考型別,=運算子將引用從一個變數傳遞到另一個變數,所以=兩邊的變數引用同一個對象;
b、對於引用相同的兩個變數,使用==運算子返回true;
c、對象的Clone方法產生一個新執行個體,返回該執行個體的引用,該執行個體的所有欄位值和原對象相同,即Clone方法得到對象的一個副本。從Object類繼承下來的保護方法MemberwiseClone返回當前對象的副本;
d、對於Clone方法返回的對象,其引用和原對象不同,==運算子返回false;
e、從Object繼承下來的Equals方法結果和==運算子相同,只是比較當前引用(this)和參數儲存的引用是否引用到了同一個對象上。
在上述代碼的基礎上,重寫Equals方法。
using System;using System.Collections.Generic;using System.Text;namespace YYS.CSharpStudy.MainConsole.AboutObject{ public class Int32Value : ICloneable { //欄位,定義欄位最好賦上初值 private int intValue = 0; /// <summary> /// 屬性 /// </summary> public int IntValue { get { return this.intValue; } set { this.intValue = value; } } /// <summary> /// 定義一個無參構造器 /// </summary> public Int32Value() { } /// <summary> /// 帶參數的構造器 /// </summary> public Int32Value(int value) { this.intValue = value; } ///// <summary> ///// 實現ICloneable介面 ///// </summary> public object Clone() { return this.MemberwiseClone(); } /// <summary> /// 覆蓋Equals方法 /// </summary> /// <param name="obj"></param> /// <returns></returns> public override bool Equals(object obj) { bool isEquals = Object.ReferenceEquals(obj, this); if (isEquals == false) { Int32Value value = obj as Int32Value; if (value != null) { isEquals = value.intValue == this.intValue; } } return isEquals; } }}
調用
using System;using YYS.CSharpStudy.MainConsole.AboutObject;namespace YYS.CSharpStudy.MainConsole{ class Program { static void Main(string[] args) { //聲明一個Int32Value類型的引用value1,指向一個執行個體 Int32Value value1 = new Int32Value(30); //聲明value2,指向value1,此時兩個引用是指向一個執行個體的 Int32Value value2 = value1; //使用==比較 Console.WriteLine(string.Format("value1和value2 {0}", value1 == value2 ? "相同" : "不相同"));//相同 //調用Clone,複製一個value1的副本,賦值給value2 //此時是兩個執行個體了 value2 = (Int32Value)value1.Clone(); //使用==比較 Console.WriteLine(string.Format("value1和value2 {0}", value1 == value2 ? "相同" : "不相同"));//不相同 //將value1賦給value2,此時他們指向同一個執行個體 value2 = value1; //使用Equals比較 Console.WriteLine(string.Format("value1和value2 {0}", value1.Equals(value2) ? "相同" : "不相同"));//相同 //調用Clone,複製一個value1的副本,賦值給value2 //此時是兩個執行個體了 value2 = (Int32Value)value1.Clone(); //使用Equals比較 Console.WriteLine(string.Format("value1和value2 {0}", value1.Equals(value2) ? "相同" : "不相同"));//相同 Console.ReadLine(); } }}
結果:
修改後的代碼:
覆蓋了Equals方法,程式運行結果則不同了:Equals不再比較兩個變數儲存的對象引用是否相同,而是比較兩個變數所引用的對象是否具有相同的屬性值。
覆蓋後的Equals執行流程是這樣的:
我們看一下覆蓋後Equals方法的具體執行流程:
a、使用Object靜態方法ReferenceEquals比較參數obj和當前對象引用(this)是否相同,如果引用相同,則必為相同對象;
b、如果變數obj和當前引用不相同,則使用as運算子,嘗試將obj類型轉換和當前對象相同的類型,轉換成功表示obj變數引用著和當前對象類相同的對象,as運算子轉換後對象的引用,否則返回null,只有同類型的對象才需要比較,不同類型的對象必然是不同的對象;
c、如果as運算子轉換對象成功,則進一步比較當前對象引用(this)和參數obj引用對象的欄位值是否相等。
由上面兩段代碼可以看出:
==和Object類的Equals方法都是比較對象的引用是否相同,並不比較對象的欄位是否相等;而Equals方法可以覆蓋,以求讓其對對象的欄位進行等值比較或者其它的比較的需求。
因此,如果需要比較兩個C#參考型別變數,除非確定需要比較的就是對象引用時才可以使用==運算子,否則應該使用對象的Equals方法,防止對象所屬的類覆蓋了這個方法。
上面是參考型別的比較,相對來說,實值型別的比較就比較純粹。實值型別是不存在引用的,所以實值型別就是比較兩個對象值是否相等。當然如果覆蓋了Equals方法就除外了。不過一般情況下,我們無需覆蓋Equals方法。對於參考型別來說,等值比較就是比較對象的引用,引用不同的兩個對象應該就是不同的對象;對於實值型別來說,比較的就是所有欄位的值,欄位值不同的兩個對象是不同的對象。只有在特殊情況下,才需要覆蓋Equals方法,已定義某個類特殊的對象比較方法。
對於覆蓋Equals方法,要注意:
注意:理論上可以用任意代碼覆蓋Equals方法,但要保證如下原則:
a、Equals只能用於對象比較,不能做其它任何用途;
b、對於兩個已存在的對象,在對象未作任何改變的情況下,無論任何時候調用Equals方法,返回的結果應該是一樣的;
c、對於對象a和b,則a.Equalse(b)和b.Equals(a)返回的結果應該是一樣的;
d、覆蓋了Equals方法,同時要覆蓋GetHashCode(方法),這個後面再詳細說明。
二、ToString()
代碼:
public class Int32Value : ICloneable { //欄位,定義欄位最好賦上初值 private int intValue = 0; /// <summary> /// 屬性 /// </summary> public int IntValue { get { return this.intValue; } set { this.intValue = value; } } /// <summary> /// 定義一個無參構造器 /// </summary> public Int32Value() { } /// <summary> /// 帶參數的構造器 /// </summary> public Int32Value(int value) { this.intValue = value; } ///// <summary> ///// 實現ICloneable介面 ///// </summary> public object Clone() { return this.MemberwiseClone(); } /// <summary> /// 重寫ToString方法 /// </summary> /// <returns></returns> public override string ToString() { return this.intValue.ToString(); //return "重寫ToString"; } }
調用:
class Program { static void Main(string[] args) { Int32Value value = new Int32Value(30); Console.WriteLine(value.ToString());//30 //Console.WriteLine(value.ToString());//重寫ToString Console.ReadLine(); } }
可以看出,ToString方法可以用任意代碼覆蓋,只要返回string即可,但是在覆蓋時也要返回符合需求的傳回值。
以上就是C#基礎知識整理:基礎知識(12) 超類Object 的內容,更多相關內容請關注topic.alibabacloud.com(www.php.cn)!