文档章节

为什么equals(Object o)相等,hashCode()必须相等

trayvon
 trayvon
发布于 2015/10/03 17:46
字数 1253
阅读 396
收藏 3

首先,int hashCode();是为了支持哈希表类的如HashMapHashTable之类的底层使用了哈希表的类。

Java Object规范中int hashCode()方法的约定类容有三个:

(1)              只要对象的equals方法所用到的信息没有修改,那么hashCode方法必须始终如一的返回一个同一整数,在同一应用程序中多次执行中,每一次执行可以不一样。

(2)              如果两个对象的equals方法想到,那么每一个对象单独调用hashCode返回的数字必须相等。

(3)              如果两个对象的equals方法不相等,hashCode方法的返回值可以相等,给不同的对象返回不同的值可以提高哈希表的性能。

下面我们以HashMap为例来看一看为什么要做这样的约定。

下图是HashMap的底层数据结构:

图像来自http://zhangshixi.iteye.com/blog/672697

通过源码和上面的示意图我们可以知道HashMap的底层是一个数组,数组的每一个元素是一个Entry组织的链表。下面是HashMappublic V put(K key, V value)方法的源代码(1.7):

 

我们观察到被标记的两条语句,首先是通过hash(Object key)方法得到一个hash值,然后通过indexFor方法定位到hash值在数组中的位置。下面是hash(Object key)的源码。我们可以看出它调用了KeyhashCode()函数。

int indexFor(int h, int length)的源码:
  static int indexFor(int h, int length) {
        return h & (length-1);
    }


从上面的内容我们知道我们用HashMap存储时是和Keyhash值相关的。如果hash值相同,那么定位数组的位置也相同(因为indexFor的返回值只和hash值和数组长度length有关,而数组的length只会在重散列时变化)

从前面我们知道数组的每一个元素都是Entry的链表,如果每一次hash值都相同,那么每一次都定位到数组的相同位置,那么链表就会很长,处理的时间也会很长。

hash值是和KeyhashCode方法相关的,所以我们就可以理解hashCode的第三条约定了,给不同对象产生不同的hashCode可以提高哈希表的性能。

我们现在再来看一看为什么如果两个对象的equals方法相等,那么每一个对象单独调用hashCode方法必须返回相同的返回值。首先我们还是先看一看HashMap取得的源代码:

public V get(Object key) {
        if (key == null)
            return getForNullKey();
        Entry<K,V> entry = getEntry(key);
 
        return null == entry ? null : entry.getValue();
    }

 

我们可以发现是可逆的,还是通过hash方法得到hash值,再通过indexFor方法定位元素在数组中的位置。想一想如果我们两个对象的equals方法相等,而hashCode方法的值可以不相等,那是不是就意味着两个逻辑上相同的对象可以放在不同的位置。那么是不是就意味着我们通过逻辑上相等的Key查找的是不同的地址(对象)。虽然这并没有什么错误,但是并不是我们实现HashMap的目的。下面通过一个例子简单的看一看会出现什么问题。

public class User
{
       private long id;
       private String name;
       private String address;
       private long phone;
       @Override
       public boolean equals(Object obj)
       {
              if(obj == this)
                     return true;
              if(! (obj instanceof User))
                     return false;
              User user = (User) obj;
              return (user.id == id && user.phone == phone && name.equals(user.name) && address.equals(user.address));
       }
       
       public User(long id, String name, String address, long phone)
       {
              super();
              this.id = id;
              this.name = name;
              this.address = address;
              this.phone = phone;
       }
 
       public long getId()
       {
              return id;
       }
       public void setId(long id)
       {
              this.id = id;
       }
       public String getName()
       {
              return name;
       }
       public void setName(String name)
       {
              this.name = name;
       }
       public String getAddress()
       {
              return address;
       }
       public void setAddress(String address)
       {
              this.address = address;
       }
       public long getPhone()
       {
              return phone;
       }
       public void setPhone(long phone)
       {
              this.phone = phone;
       }
       
       public static void main(String[] args)
       {
              HashMap<User, String> map = new HashMap<User,String>();
              map.put(new User(1,"tom","china",13888888888L),"hello world");
              System.out.println(map.get(new User(1,"tom","china",13888888888L)));     
       }      
}

我们的本意是通过User来查找hello world,但是并没有如我们所愿对吗?为什么呢?因为我们重写了Userequals方法,但是没有重写hashCode方法,所以用的是继承自Object类的hashCode方法。因为是用new所以地址并不一样,hashCode的值自然也就不相同了。所以定位到了其他的位置,什么都没有找到返回null

 


© 著作权归作者所有

trayvon
粉丝 16
博文 142
码字总数 216677
作品 1
程序员
私信 提问
Java 中的equal()和hascode()方法

equals()反映的是对象或变量具体的值,即两个对象里面包含的值--可能是对象的引用,也可能是值类型的值。 而hashCode()是对象或变量通过哈希算法计算出的哈希值。 之所以有hashCode方法,是因...

vshcxl
2016/10/25
11
0
java重写equals()方法和hashCode()方法

1.equals()方法和hashCode()方法是什么? equals()和hashCode()都是是Java中万物之源Object类中的方法; equals方法用于比较两个对象是否相同,Object类中equals方法的实现是比较引用地址来判...

天王盖地虎626
06/19
52
0
HashCode和equal方法

equals()反映的是对象或变量具体的值,即两个对象里面包含的值--可能是对象的引用,也可能是值类型的值。 而hashCode()是对象或变量通过哈希算法计算出的哈希值。 之所以有hashCode方法,是因...

Vincent-Duan
2016/10/29
8
0
重写equal 的同时为什么必须重写hashcode?

hashCode是编译器为不同对象产生的不同整数,根据equal方法的定义:如果两个对象是相等(equal)的,那么两个对象调用hashCode必须产生相同的整数结果,即:equal为true,hashCode必须为tru...

未明儿
2014/03/30
89
1
java中hashcode()和equals()的详解

今天下午研究了半天hashcode()和equals()方法,终于有了一点点的明白,写下来与大家分享(zhaoxudong 2008.10.23晚21.36)。 1. 首先equals()和hashcode()这两个方法都是从object类中继承过来...

梦想生活
2012/12/13
93
1

没有更多内容

加载失败,请刷新页面

加载更多

JAVA 编写redisUtils工具类,防止高并发获取缓存出现并发问题

import lombok.extern.slf4j.Slf4j;import org.springframework.data.redis.core.BoundHashOperations;import org.springframework.data.redis.core.BoundValueOperations;import org.......

huangkejie
37分钟前
5
0
JMM内存模型(一)&volatile关键字的可见性

在说这个之前,我想先说一下计算机的内存模型: CPU在执行的时候,肯定要有数据,而数据在内存中放着呢,这里的内存就是计算机的物理内存,刚开始还好,但是随着技术的发展,CPU处理的速度越...

走向人生巅峰的大路
54分钟前
95
0
你对AJAX认知有多少(2)?

接着昨日内容,我们几天继续探讨ajax的相关知识点 提到ajax下面几个问题又是必须要了解的啦~~~ 8、在浏览器端如何得到服务器端响应的XML数据。 通过XMLHttpRequest对象的responseXMl属性 9、 ...

理性思考
今天
5
0
正则表达式基础(一)

1.转义 转义的作用: 当某个字符在表达式中具有特殊含义,例如字符串引号中出现了引号,为了可以使用这些字符本身,而不是使用其在表达式中的特殊含义,则需要通过转义符“\”来构建该字符转...

清自以敬
今天
4
0
idea中@Data标签getset不起作用

背景:换电脑以后在idea中有@data注解都不生效 解决办法:idea装个插件 https://blog.csdn.net/seapeak007/article/details/72911529...

栾小糖
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部