HashCode和equals()

2017-03-01  本文已影响74人  米刀灵

Java中的equals方法和hashCode方法是Object中的,所以每个对象都是有继承这两个方法的,有时候我们需要实现特定需求,可能要重写这两个方法。

比如:HashMap、HashTable、HashSet,所以涉及到使用hash值进行优化存储的地方,都会用到hashCode。
1.首先调用对象的hashCode()方法获得该对象的哈希码表。
2.然后根据哈希吗找到相应的存储区域。
3.最后取得该存储区域内的每个元素与该对象进行equals方法比较。
这样就不用遍历集合中的所有元素就可以得到结论,可见HashSet集合具有很好的对象检索性能。

hash与equals的关系:
hashCode就好比字典里每个字的索引,equals()好比比较的是字典里同一个字下的不同词语。

下面来看一下一个具体的例子:
RectObject对象:

package com.weijia.demo;  
  
public class RectObject {  
    public int x;  
    public int y;  
    public RectObject(int x,int y){  
        this.x = x;  
        this.y = y;  
    }  
    @Override  
    public int hashCode(){  
        final int prime = 31;  
        int result = 1;  
        result = prime * result + x;  
        result = prime * result + y;  
        return result;  
    }  
    @Override  
    public boolean equals(Object obj){  
        if(this == obj)  
            return true;  
        if(obj == null)  
            return false;  
        if(getClass() != obj.getClass())  
            return false;  
        final RectObject other = (RectObject)obj;  
        if(x != other.x){  
            return false;  
        }  
        if(y != other.y){  
            return false;  
        }  
        return true;  
    }  
}  

我们重写了父类Object中的hashCode和equals方法,看到hashCode和equals方法中,如果两个RectObject对象的x,y值相等的话他们的hashCode值是相等的,同时equals返回的是true;
下面是测试代码:

package com.weijia.demo;  
import java.util.HashSet;  
public class Demo {  
    public static void main(String[] args){  
        HashSet<RectObject> set = new HashSet<RectObject>();  
        RectObject r1 = new RectObject(3,3);  
        RectObject r2 = new RectObject(5,5);  
        RectObject r3 = new RectObject(3,3);  
        set.add(r1);  
        set.add(r2);  
        set.add(r3);  
        set.add(r1);  
        System.out.println("size:"+set.size());  
    }  
}  

最后我们在来看一下hashCode造成的内存泄露的问题:看一下代码:

package com.weijia.demo;  
import java.util.HashSet;  
public class Demo {  
    public static void main(String[] args){  
        HashSet<RectObject> set = new HashSet<RectObject>();  
        RectObject r1 = new RectObject(3,3);  
        RectObject r2 = new RectObject(5,5);  
        RectObject r3 = new RectObject(3,3);  
        set.add(r1);  
        set.add(r2);  
        set.add(r3);  
        r3.y = 7;  
        System.out.println("删除前的大小size:"+set.size());  
        set.remove(r3);  
        System.out.println("删除后的大小size:"+set.size());  
    }  
}  

运行结果:
删除前的大小size:3
删除后的大小size:3
调用了remove删除r3对象,以为删除了r3,但事实上并没有删除,這樣多次这样操作之后,内存就爆了。因為在调用remove方法的时候,会先使用对象的hashCode值去找到这个对象,然后进行删除,但我们在修改了r3对象的y属性的值,又因为RectObject对象的hashCode方法中有y值参与运算,所以r3对象的hashCode就发生改变了,所以remove方法中并没有找到r3了,所以删除失败。即r3的hashCode变了,但是他存储的位置没有更新,仍然在原来的位置上,所以当我们用他的新的hashCode去找肯定是找不到了。


要点:
Object中的hashCode方法返回的是对象本地内存地址的换算结果。
HashSet判断要放入的元素是否相等:
1.hashcode是否相等,不相等放入。
2.如果hashcode相等,判断equals方法和==方法,如果都不相等放入。equals和==方法只要有一个相等,HashSet认为是相同的元素。

上一篇 下一篇

猜你喜欢

热点阅读