HashCode

HashCode作用

数据结构Set可以保证其中的元素是无序且不重复的。如何保证其中元素不重复,有两种方法。

  • 在插入新元素的时候,依次和Set中元素调用equals方法进行比较。不过这种方法在数据量较小的情况。

  • 在插入新元素的时候,计算新元素的HashCode值。通过HashCode的值寻找其对应的位置,如果对应的位置有元素,则再次调用equals方法来进行判断。

简言之:HashCode的作用就是用来寻址

  • Java中的hashCode方法就是根据一定的规则将与对象相关的信息(比如对象的存储地址,对象的 字段等)映射成一个数值,这个数值称作为散列值

HashCode设计中的矛盾:

一个对象势必会存在若干个属性,

  • 如果我们将所有属性进行散列,这必定会是一个糟糕的设计,因为对象的hashCode方法无时无刻不是在被调用,如果太多的属性参与散列,那么需要的操作数时间将会大大增加,这将严重影响程序的性能。

  • 如果较少属相参与散列,散列的多样性会削弱,会产生大量的散列"冲突",除了不能够很好的利用空间外,在某种程度也会影响对象的查询效率。

HashCode 和 equals:

equals所需要遵循的规则:

  • 对称性: 如果x.equals(y)返回是"true",那么y.equals(x)也应该返回是"true"。

  • 反射性: x.equals(x)必须返回是"true"。

  • 类推性: 如果x.equals(y)返回是"true",而且y.equals(z)返回是"true",那么z.equals(x)也应该返回是"true"。

  • 一致性: 如果x.equals(y)返回是"true",只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是"true"。

  • 任何情况下,x.equals(null),永远返回是"false";x.equals(和x不同类型的对象)永远返回是"false"。

hashCode 所需要遵循的规则:

  • 在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,则对该对象调用hashCode方法多次,它必须始终如一地返回同一个整数。

  • 如果两个对象根据equals(Object o)方法是相等的,则调用这两个对象中任一对象的hashCode方法必须产生相同的整数结果。

  • 如果两个对象根据equals(Object o)方法是不相等的,则调用这两个对象中任一个对象的hashCode方法,不要求产生不同的整数结果。但如果能不同,则可能提高散列表的性能。

equals和hashCode联系:

  • 如果x.equals(y)返回“true”,那么x和y的hashCode()必须相等。

  • 如果x.equals(y)返回“false”,那么x和y的hashCode()有可能相等,也有可能不等。

HashCode的实现:

Java String类的HashCode实现:


public int hashCode() {  
    int h = hash;  
    if (h == 0) {  
        int off = offset;  
        char val[] = value;  
        int len = count;  

            for (int i = 0; i < len; i++) {  
                h = 31*h + val[off++];  
            }  
            hash = h;  
        }  
        return h;  
    }
}
  • 上述方法可以总结为: s[0]31^(n-1) + s[1]31^(n-2) + ... + s[n-1]

  • 为什么这里用31,而不是其它数呢?《Effective Java》是这样说的:之所以选择31,是因为它是个奇素数,如果乘数是偶数,并且乘法溢出的话,信息就会丢失,因为与2相乘等价于移位运算。使用素数的好处并不是很明显,但是习惯上都使用素数来计算散列结果。31有个很好的特性,就是用移位和减法来代替乘法,可以得到更好的性能:31*i==(i<<5)-i。现在的JVM可以自动完成这种优化。

Java Object类的HashCode实现:

HashCode In redis_go

采用三方库来实现:

Code Sample:


type ComplexStruct struct {
    Name     string
    Age      uint
    Metadata map[string]interface{}
}

v := ComplexStruct{
    Name: "mitchellh",
    Age:  64,
    Metadata: map[string]interface{}{
        "car":      true,
        "location": "California",
        "siblings": []string{"Bob", "John"},
    },
}

hash, err := Hash(v, nil)
if err != nil {
    panic(err)
}

fmt.Printf("%d", hash)

//Output: 6691276962590150517

reference

powered by Gitbook该文件修订时间: 2019-07-05 09:33:43

results matching ""

    No results matching ""