0
点赞
收藏
分享

微信扫一扫

hashSet重写-利用String的hashcode与equals方法-实现定向去重


一.String重写了hashcode与equals方法

String类中的equals()方法的源码如下

  

public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}

通过观察equals()方法的源码我们可以看出,该方法去比较两个对象时,首先先去判断两个对象是否具有相同的地址,如果是同一个对象的引用,则直接放回true;如果地址不一样,则证明不是引用同一个对象,接下来就是挨个去比较两个字符串对象的内容是否一致,完全相等返回true,否则false。

String类中hashCode()方法的源码如下:
     public int hashCode() {
        int h = hash;
        if (h == 0 && count > 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;
    }

以上是String类中重写的hashCode()方法,以31为权,每一位为字符的ASCII值进行运算,用自然溢出来等效取模,哈希计算公式可以计为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可以自动完成这种优化。

注意上面代码有两个问题:

1.hash码采用int保存可能会有重复
System.out.println("ABCDEa123abc".hashCode()); // 165374702
System.out.println("ABCDFB123abc".hashCode()); // 165374702

2.对入具有reverse关系的字符串会返回相同的hashcode,如:  字符串"gdejicbegh"与字符串"hgebcijedg"具有相同的hashCode()返回值-801038016

在Object类中的hashCode()方法是返回对象的32位JVM内存地址,也就是说如果我们不去重写该方法,将会返回该对象的32位JVM内存地址。所以我们通常要将hashCode()方法与equals()方法一起重写,以维护hashCode方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
 

 

 

 

 

 

hashSet重写-利用String的hashcode与equals方法-实现定向去重_i++

 

 

当 具体逻辑是设定两个set类;

当string的那个set存入时将会返回ture 

另一个set存入对象即可

从而在不修改类的基础上重写hashcode与equals()方法

 

举报

相关推荐

0 条评论