zoukankan      html  css  js  c++  java
  • java中的hashcode()和equals()

    equals()和hashcode()都继承自object类。

    equals()

    equals()方法在object类中定义如下:

    1 public boolean equals(Object obj) {
    2     return (this == obj);
    3 } 

    这是对两个对象的地址值进行的比较(即比较对象的引用是否相同)。

    String 、Math、Integer、Double.......等这些封装类在使用equals()方法时,已经覆盖了object类的equals()方法。比如在String类中如下:

     1 public boolean equals(Object anObject) {
     2         if (this == anObject) {
     3             return true;
     4         }
     5         if (anObject instanceof String) {
     6             String anotherString = (String)anObject;
     7             int n = value.length;
     8             if (n == anotherString.value.length) {
     9                 char v1[] = value;
    10                 char v2[] = anotherString.value;
    11                 int i = 0;
    12                 while (n-- != 0) {
    13                     if (v1[i] != v2[i])
    14                         return false;
    15                     i++;
    16                 }
    17                 return true;
    18             }
    19         }
    20         return false;
    21     }

    很明显,这是进行的内容比较,而已经不再是地址的比较。依次类推Double、Integer、Math。。。。等等这些类都是重写了equals()方法的,从而进行的是内容的比较。基本类型是进行值的比较。
    值得注意的是,Java语言对equals()的要求如下,这些要求在《effective java》这本书中有详细的说明:
    • 对称性:如果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”。
    以上这五点是重写equals()方法时,必须遵守的准则,如果违反会出现意想不到的结果,请大家一定要遵守。

    hashcode()

    hashcode() 方法,在object类中定义如下:  

    1 public native int hashCode();

    这是一个本地方法,它的实现是根据本地机器相关的。

    String、 Integer、Double。。。。等等这些类都是覆盖了hashcode()方法的。例如在String类中定义的hashcode()方法如下:

     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;
       }

    解释一下这个程序(String的API中写到):
    s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
    使用 int 算法,这里 s[i] 是字符串的第 i 个字符,n 是字符串的长度,^ 表示求幂。(空字符串的哈希码为 0)

    比较

    equals()相等的两个对象,hashcode()一定相等;
    equals()方法不相等的两个对象,hashcode()有可能相等。
    反过来:hashcode()不等,一定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。

    在object类中,hashcode()方法是本地方法,返回的是对象的地址值(不是实际的物理地址),而equals()方法比较的也是两个对象的地址值,如果equals()相等,说明两个对象地址值也相等,当然 hashcode()也就相等了;在String类中,equals()返回的是两个对象内容的比较,当两个对象内容相等时, Hashcode()方法根据String类的重写代码的分析,也可知道hashcode()返回结果也会相等。以此类推,可以知道Integer、Double等封装类中经过重写的equals()和hashcode()方法也同样适合于这个原则。当然没有经过重写的类,在继承了object类的equals()和hashcode()方法后,也会遵守这个原则。

    hashcode也就是“哈希码”的作用就是为支持数据结构中的哈希表结构而存在的,通过给每个对象分配一个唯一的索引来提高查询的效率。Hashtable、HashMap、HashSet、LinkedHashMap等带有hash的容器要特别注意hashcode。简单来说,hashcode是对属性比较多的对象的equals方法的替代.在hashset中不允许出现重复对象,元素的位置也是不确定的。在hashset中又是怎样判定元素是否重复的呢?

    在java的集合中,判断两个对象是否相等的规则是:
    1),判断两个对象的hashCode是否相等
          如果不相等,认为两个对象也不相等,完毕
          如果相等,转入2)
    (这一点只是为了提高存储效率而要求的,其实理论上没有也可以,但如果没有,实际使用时效率会大大降低)
    2),判断两个对象用equals运算是否相等
          如果不相等,认为两个对象也不相等
          如果相等,认为两个对象相等(equals()是判断两个对象是否相等的关键)
     

     1 import java.util.*;
     2 public class HashSetTest {
     3         public static void main(String[] args) {
     4                 HashSet hs=new HashSet();
     5                 hs.add(new Student(1,"zhangsan"));
     6                 hs.add(new Student(2,"lisi"));
     7                 hs.add(new Student(3,"wangwu"));
     8                 hs.add(new Student(1,"zhangsan"));
     9                 Iterator it=hs.iterator();
    10                 while(it.hasNext()) {
    11                         System.out.println(it.next());
    12                 }
    13         }
    14 }
    15 class Student {
    16        int num;
    17         String name;
    18         Student(int num,String name) {
    19                 this.num=num;
    20                 this.name=name;
    21         }
    22         public String toString() {
    23                 return num+":"+name;
    24         }     
    25  }      
    -----------OUTPUT-----------
    1:zhangsan
    1:zhangsan
    2:lisi
    3:wangwu

    问题出现了,为什么hashset添加了相等的元素呢?
    这是因为在根据hashcode()对两次建立的new Student(1,"zhangsan")对象进行比较时,生成的是不同的哈希码值,所以hashset把他当作不同的对象对待了,当然此时的 equals()方法返回的值也不等 。那么为什么会生成不同的哈希码值呢?原因就在于我们自己写的Student类并没有重新自己的hashcode()和equals()方法,所以在比较时,是继承的object类中的 hashcode()方法。比较的是对象的地址(引用地址),使用new方法创建对象,两次生成的当然是不同的对象了,造成的结果就是两个对象的hashcode()返回的值不一样。所以根据第一个准则,hashset会把它们当作不同的对象对待,自然也用不着第二个准则进行判定了。
    在Student类中重写hashcode()和equals()方法。

     1 class Student {
     2        int num;
     3         String name;
     4         Student(int num,String name) {
     5                 this.num=num;
     6                 this.name=name;
     7         }
     8         public int hashCode() {
     9                 return num*name.hashCode();
    10         }
    11         public boolean equals(Object o) {
    12                 Student s=(Student)o;
    13                 return num==s.num && name.equals(s.name);
    14         } 
    15         public String toString() {
    16                 return num+":"+name;
    17         }     
    18  }      
    -----------OUTPUT-----------
    3:wangwu
    2:lisi
    1:zhangsan

    根据重写的方法,即便两次调用了new Student(1,"zhangsan"),我们在获得对象的哈希码时,根据重写的方法hashcode(),获得的哈希码肯定是一样的。
    当然根据equals()方法我们也可判断是相同的。所以在向hashset集合中添加时把它们当作重复元素看待了。可以看到重复元素的问题已经消除。


     参考自http://www.iteye.com/topic/257191

  • 相关阅读:
    centos7.6 使用yum安装mysql5.7
    解决hadoop本地库问题
    docker-compose 启动警告
    docker 安装zabbix5.0 界面乱码问题解决
    docker 部署zabbix问题
    zookeeper 超时问题
    hbase regionserver异常宕机
    (转载)hadoop 滚动升级
    hadoop Requested data length 86483783 is longer than maximum configured RPC length
    zkfc 异常退出问题,报错Received stat error from Zookeeper. code:CONNECTIONLOSS
  • 原文地址:https://www.cnblogs.com/wangyingli/p/4873984.html
Copyright © 2011-2022 走看看