首页 > 代码库 > 关于hashCode与equals

关于hashCode与equals


首先我得说明,在我们自己写得类中你能够复写这两个方法,此时从语法的角度来说,他们没关系。
在object中
public native int hashCode();
public boolean equals(Object obj) {
        return (this == obj);
}

两个准则

在java集合中
判定两个对象是否相等须要下面两步;
1 hashCode的值是否相等,
  假设不相等,那么不用说,两个对象肯定不相等;假设hashCode的值相等,那么看第二步;
2 equals的值是否相等;
  假设equals的值相等,那么两个对象相等;
  若是equals的值不相等,那么两个对象不相等;
(我们能够看到,equals起最后的作用)
那就有一个问题了,既然equals起最后的作用我们在集合类中推断两个对象是否相等的时候,就直接调用equals就可以,为什么还有hashcode呢?

由于有的时候equals方法比較复杂,我们假设通过hashcode方法已经说明两个对象不相等了就能够不用调用equals了


hashCode是个本地方法,返回的结果是对对象存储位置的一系列复杂运算;

而equals就是单纯的比較两个对象的地址值是否相等;
看到这里就存在几个准则
假设equals相等,那么hashCode一定相等;  地址值已经相等了,再怎么计算它都是相等的
假设hashCode相等了,equals不一定相等;  4%3=1  1%3=1 看到了吧,不同的值经过同样的运算法则,有可能取得同样的值

代码说明

首先我们看看字符串的equals与hashCode
public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String) anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                            return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

      /**
     * Returns a hash code for this string. The hash code for a
     * <code>String</code> object is computed as
     * <blockquote><pre>
     * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
     * </pre></blockquote>
     * using <code>int</code> arithmetic, where <code>s[i]</code> is the
     * <i>i</i>th character of the string, <code>n</code> is the length of
     * the string, and <code>^</code> indicates exponentiation.
     * (The hash value of the empty string is zero.)
     *
     * @return  a hash code value for this object.
     */
    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }


在读hashCode方法的凝视的时候我一直不明确
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]         //n代码字符串长度  ^代码乘方或者说幂
  for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
从数学上说,这两个有什么关系
后来我验证了一下,两种方法返回的int值是一样的 为什么?不明觉厉!

     以下这个样例的结果我已经写到凝视里了
        String s1=new String("zhaoxudong");
        String s2=new String("zhaoxudong");
        String s3="zhaoxudong";
        String s4="zhaoxudong";
        System.out.println(s1==s2);      //两个new出来的对象 s1 s2里面放的是两个不同对象的地址 自然不相等
        System.out.println(s1==s3);         //false 一个指向堆内存 一个指向常量池
        System.out.println(s3==s4);      //true 都在常量池中
        System.out.println("##### ");
        System.out.println(s1.equals(s2));//true
        System.out.println(s1.hashCode());//s1.hashcode()等于s2.hashcode()等于s3.hashcode()
        System.out.println(s2.hashCode());
        System.out.println(s3.hashCode());
    
        Set hashset=new HashSet();
        hashset.add(s1);
        hashset.add(s2);
        Iterator it=hashset.iterator();
        while(it.hasNext())
            System.out.println(it.next());  //仅仅打印出一个


再看这个
import java.util.HashSet;
import java.util.Set;
import java.util.Iterator;

public class hashCode
{
    public static void main(String[] args)
    {

        HashSet hs=new HashSet();
        hs.add(new Student(1,"zhangsan"));
        hs.add(new Student(2,"lisi"));
        hs.add(new Student(3,"wangwu"));
        hs.add(new Student(1,"zhangsan"));
 
        Iterator it=hs.iterator();
        while(it.hasNext())
            System.out.println(it.next());
      }
}
public class Student
   {
     int num;
     String name;
     Student(int num,String name)
                {
                this.num=num;
                 this.name=name;
                 }
              public String toString()
                {
                    return num+":"+name;
                 }
   }   


执行结果
1:zhangsan
3:wangwu
1:zhangsan
2:lisi
两个张三?
由于,hash的add方法在增加新元素的时候,先找Student的hashCode方法,结果没有,那就调用object的hashCode方法,两个zhangsan都是new出来的,自然不是一个对象喽,所以就加进去了!
怎么改?
给stuend类中增加下面两个方法
public int hashCode()
{
            return num*name.hashCode();
}
public boolean equals(Object o)
{
            Student s=(Student)o;
            return num==s.num && name.equals(s.name);
} 


可是,大家得记住,equals相等,hashcode就一定相等这个准则,所以两个方法不要乱写!

改完之后,就仅仅有一个zhangsan了。


參考资料

http://www.iteye.com/topic/257191

关于hashCode与equals