《.NET框架程序设计》第6章 通用对象操作
所有对象通用的操作:对象等值,唯一,散列码,克隆。
6.1 对象的等值性和唯一性
System.Object的Equals方法是,如果两个引用指向同一个对象,返回true,否则返回false。
6.1.1 为基类没有重写Object.Equals方法的引用类型实现Equals
首先判断,两个对象是否null;其次判断两个对象的类型相同与否;然后进行类型转化,判断两个对象的字段相等与否;最后高兴的话,重载==和!=操作符。
这里的类型转化,不可能抛出异常,因为前面比较过两个对象的类型。
6.1.2 为基类重写了Object.Equals方法的引用类型实现Equals
这里的判断思路和上一节相同,唯一差别是要比较基类型中定义的字段。
6.1.3 为值类型实现Equals方法
值类型都继承于System.ValueType,ValueType的Equals方法实现思路是:
首先判断,要比较对象是否null;其次判断两个对象的类型相同与否;然后取得该类型所有的公有和私有实例字段,进行字段比较;
虽然ValueType的Equals方法适用大多数情况,但我们自己实现Equals方法,程序执行效率会更高。因为自定义的值类型,会包含引用类型,进行比较时会涉及到装箱拆箱
6.1.4 Equals方法与==/!=操作符的实现总结
编译器为基元类型提供了==/!=操作符的重写。 自定义类型呢,自己慢慢重载吧。
6.1.5 对象唯一性识别
System.Object.ReferenceEquals方法用来判断两个引用是否指向同一个实例。
Int32 x=5;
Console.WriteLine(Object.ReferenceEquals(x,x))//false
Console.WriteLine(Object.ReferenceEquals(x,x))//false
因为x被两次装箱到不同的对象中去了。
总结:重写对象Equals方法,不练习多次,很容易忘记,考虑细节挺多,费脑。还是记下来,下次照着例子写就好。
6.2对象的散列码
为什么会有散列码?
因为任何对象实例都能被放入一个散列表集合。散列表以键值对存储,散列码就是键。
重写Equals方法的同时,也要重写GetHashCode方法。
重写Equals方法和GetHashCode方法是因为System.Collections.Hashtable类型的实现要求任何两个相等的对象都必须有相等的散列码值。
实现类型实例的散列码算法时,我们应该尽量遵循以下原则:
算法取得的数值有良好的随机分布,这样散列表可以获得最佳性能。
算法应该使用最少一个字段。
算法中使用的字段都应该是恒定不变。
两个有着相同文本的String对象应该返回同样的散列码值。
System.Object中实现的GetHashCode方法返回的是一个应用程序域(AppDomain)范围内确保唯一的值。
System.ValueType的GetHashCode方法使用反射来返回定义在类型中第一个实例字段的散列码值。
我们最好自己来写GetHashCode方法,自己写的执行效率比自带的高。
因为任何对象实例都能被放入一个散列表集合。散列表以键值对存储,散列码就是键。
重写Equals方法的同时,也要重写GetHashCode方法。
重写Equals方法和GetHashCode方法是因为System.Collections.Hashtable类型的实现要求任何两个相等的对象都必须有相等的散列码值。
实现类型实例的散列码算法时,我们应该尽量遵循以下原则:
算法取得的数值有良好的随机分布,这样散列表可以获得最佳性能。
算法应该使用最少一个字段。
算法中使用的字段都应该是恒定不变。
两个有着相同文本的String对象应该返回同样的散列码值。
System.Object中实现的GetHashCode方法返回的是一个应用程序域(AppDomain)范围内确保唯一的值。
System.ValueType的GetHashCode方法使用反射来返回定义在类型中第一个实例字段的散列码值。
我们最好自己来写GetHashCode方法,自己写的执行效率比自带的高。
合乎自然而生生不息。。。