zoukankan      html  css  js  c++  java
  • 关于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

  • 相关阅读:
    《领域驱动设计的原则与实践》读书笔记(一)
    asp.net identity UserSecurityStamp 的作用
    Python Django Apache配置
    SQL语句优化(转载)
    【转】性能测试,影响 TPS 的一些因素
    【转】接口测试总结
    【转】两款 Web 前端性能测试工具
    【转】工作中使用Trepn Power Profiler的应用总结
    【转】nGrinder 简易使用教程
    Http协议状态码总结
  • 原文地址:https://www.cnblogs.com/gcczhongduan/p/4044141.html
Copyright © 2011-2022 走看看