zoukankan      html  css  js  c++  java
  • Effective C# Item10:理解GetHashCode()方法的缺陷

        GetHashCode()方法的用途:为一个基于散列的集合定义键的散列值,典型的散列集合包括HashTable和Dictionary。如果我们定义的类型在散列集中不会被用作键的话,那么不用关心它的GetHashCode()方法是否高效和正确。

        作为类型的散列值,它应该满足以下三条规则:

    1. 如果两个对象相等,那么它们必须产生相同的散列值,否则,这样的三列码不能用来查找集合中的对象。
    2. 对于任何一个对象A,A.GetHashCode()方法必须是一个实例不变式(invariant),即不管在A上调用什么方法,A.GetHashCode()都必须总是返回相同的值,,者可以确保放在“散列桶”中的对象总是位于正确的“散列桶”中。
    3. 对于所有的输入,散列函数应该在所有的整数中产生一个随机的分布,这样,我们才能从一个散列容器上获得效率的提升。

        通过上述三条规则,我们可以理解:为什么我们在重写了类型实例的Equals方法后,要重写GetHashCode()方法,因为如果不重写,会违反上述规则1。

        引用类型和值类型的基类,都对GetHashCode()方法提供了默认的实现。System.Object类的实现方式:使用一个内部字段来产生散列值,系统创建的每一个对象在创建时都会有一个唯一的对象键,这些键从1开始,每创建一个新的对象,键值就会增1,对象标识字段在对象创建后,是不可以再更改的,而GetHashCode()方法,就会将这个对象键值返回;而System.ValueType提供的默认方式:返回类型中定义的第一个字段的散列码。

       我们来分析上述默认实现是否满足了散列值的三条规则,首先,对于System.Object,在不重写Equals的情况下,是满足规则1的;规则2是可以满足的;规则3则只有在大量对象的情况下,才会满足,否则,散列值会集中在整数的低端。

       然后,我们再看ValueType,在不重写Equals,或者重写Equals并且将第一个字段作为比较条件时,是满足规则1的;如果类型中的第一个字段是只读的,那么是可以满足规则2的;至于是否可以满足规则3,就要看类型中第一个字段是否在整数中有一个随机分布了。

        我们可以自己重写GetHashCode()方法,但是一定要满足上述3条规则,其中规则1和规则2可以保证生成的散列码是正确的;规则3可以保证生成的散列码是高效的。

  • 相关阅读:
    java+opencv实现图像灰度化
    java实现高斯平滑
    hdu 3415 单调队列
    POJ 3368 Frequent values 线段树区间合并
    UVA 11795 Mega Man's Mission 状态DP
    UVA 11552 Fewest Flops DP
    UVA 10534 Wavio Sequence DP LIS
    UVA 1424 uvalive 4256 Salesmen 简单DP
    UVA 1099 uvalive 4794 Sharing Chocolate 状态DP
    UVA 1169uvalive 3983 Robotruck 单调队列优化DP
  • 原文地址:https://www.cnblogs.com/wing011203/p/1643719.html
Copyright © 2011-2022 走看看