equals()与hashCode()

1.equals()和hashCode()区别

equals():反映的是对象或变量具体的值,即两个对象里面包含的值--可能是对象的引用,也可能是值类型的值。

hashCode():计算出对象实例的哈希码,并返回哈希码,又称为散列函数。根类Object的hashCode()方法的计算,依赖于对象实例的iD(内存地址),故每个Object对象的hashCode都是唯一的;当然,当对象所对应的类重写了

hashCode()方法时,结果就截然不同了。

之所以有hashCode方法,它的主要作用是为了配合基于散列的集合一起正常运行,提高查找效率,是因为在批量的对象比较中,hashCode要比equals来得快,很多集合都用到了hashCode,比如HashTable。
 
两个obj,如果equals()相等,hashCode()一定相等。
两个obj,如果hashCode()相等,equals()不一定相等(Hash散列值有冲突的情况,虽然概率很低)。


所以:

可以考虑在集合中,判断两个对象是否相等的规则是:
第一步,如果hashCode()相等,则查看第二步,否则不相等;
第二步,查看equals()是否相等,如果相等,则两obj相等,否则还是不相等。


一、首先equals()和hashCode()这两个方法都是从object类中继承过来的。

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

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

       Object类中的hashCode方法
public native int hashCode();

二、Java语言对equals()的要求如下,这些要求是必须遵循的:

  A 对称性:如果x.equals(y)返回是“true”,那么y.equals(x)也应该返回是“true”。

  B 反射性:x.equals(x)必须返回是“true”。

  C 类推性:如果x.equals(y)返回是“true”,而且y.equals(z)返回是“true”,那么z.equals(x)也应该返回是“true”。

  D 一致性:如果x.equals(y)返回是“true”,只要x和y内容一直不变,不管你重复x.equals(y)多少次,返回都是“true”。

  任何情况下,x.equals(null),永远返回是“false”;x.equals(和x不同类型的对象)永远返回是“false”。

二、equals()相等的两个对象,hashcode()一定相等;

  反过来:hashCode()不等,一定能推出equals()也不等;

  hashcode()相等,equals()可能相等,也可能不等。



2.为什么选择hashCode方法

hashCode主要为了提高查询效率

以java.lang.Object来理解,JVM每new一个Object,它都会将这个Object丢到一个Hash哈希表中去,这样的话,

下次做Object的比较或者取这个对象的时候,它会根据对象的hashCode再从Hash表中取这个对象。这样做的目的

是提高取对象的效率。

具体过程是这样:

1. new Object(),JVM根据这个对象的Hashcode值,放入到对应的Hash表对应的Key上,如果不同的对象确产生了相同的hash值,也就是发生了Hash key相同导致冲突的情况,那么就在这个Hash key的地方产生一个链表,将所有产生相同hashCode的对象放到这个单链表上去,串在一起。

2. 比较两个对象的时候,首先根据他们的hashCode去hash表中找他的对象,当两个对象的hashCode相同,那么就是说他们这两个对象放在Hash表中的同一个key上,那么他们一定在这个key上的链表上。那么此时就只能根据Object的equal方法来比较这个对象是否equal。当两个对象的hashCode不同的话,肯定他们不能equal.

list是可以重复的,set是不可以重复的。
那么set存储数据的时候是怎样判断存进的数据是否已经存在。

先调用hashCode()进行散列,再调用equals()具体比较每一个对象;

 存一个数据就调用一次hashCode()方法,得到一个hashCode值及存入的位置。

 如果该位置不存在数据那么就直接存入,否则调用一次equals()方法,不相同则存,相同不存。

这样下来整个存储下来不需要调用几次equals方法,虽然多了几次hashcode方法,但相对于前面来讲效率高了不少。
因为向HashSet集合中添加一个对象时,

要先计算出对象的哈希码和根据这个哈希码确定对象在集合中的存放位置为了保证一个类的实例对象能在

HashSet正常存储,

要求这个类的两个实例对象用equals()方法比较的结果相等时,他们的哈希码也必须相等;

也就是说,如果obj1.equals(obj2)的结果为true,那么以下表达式的结果也要为true:

    obj1.hashCode() == obj2.hashCode()

换句话说:当我们重写一个对象的equals方法,就必须重写他的hashCode方法,如果不重写他的hashCode方法的话, Object对象中的hashCode方法始终返回的是一个对象的hash地址,而这个地址是永远不相等的。所以这时候即使是重写了equals方法,也不会有特定的效果的,因为hashCode方法如果都不想等的话,就不会调用equals方法进行比较了,所以没有意义了。



3.为什么要重写equals方法

因为Object的equal方法默认是两个对象的引用的比较,意思就是指向同一内存,地址则相等,否则不相等;如果你现在需要利用对象里面的值来判断是否相等,则重载equal方法。说道这个地方我相信很多人会有疑问,相信大家都被String对象的equals()方法和"=="纠结过一段时间,当时我们知道String对象中equals方法是判断值的,而==是地址判断。

那照这么说equals怎么会是地址的比较呢?

那是因为实际上JDK中,String、Math等封装类都对Object中的equals()方法进行了重写。我们先看看Object中equals方法的源码:

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

我们都知道所有的对象都拥有标识(内存地址)和状态(数据),同时“==”比较两个对象的的内存地址,所以说使用Object的equals()方法是比较两个对象的内存地址是否相等,即若object1.equals(object2)为true,则表示equals1和equals2实际上是引用同一个对象。虽然有时候Object的equals()方法可以满足我们一些基本的要求,但是我们必须要清楚我们很大部分时间都是进行两个对象的比较,这个时候Object的equals()方法就不可以了,所以才会有String这些类对equals方法的改写,依次类推Double、Integer、Math。。。。等等这些类都是重写了equals()方法的,从而进行的是内容的比较


3.改写equals时总是要改写hashCode

java.lang.Object中对hashCode的约定:

1. 在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,则对该对象调用hashCode方法多次,它必须始终如一地返回同一个整数。

2. 如果两个对象根据equals(Object o)方法是相等的,则调用这两个对象中任一对象的hashCode方法必须产生相同的整数结果。

3. 如果两个对象根据equals(Object o)方法是不相等的,则调用这两个对象中任一个对象的hashCode方法,不要求产生不同的整数结果。但如果能不同,则可以提高散列表的性能。

根据上一个问题,实际上我们已经能很简单的解释这一点了,比如改写String中的equals为基于内容上的比较而不是内存地址的话,那么虽然equals相等,但并不代表内存地址相等,由hashcode方法的定义可知内存地址不同,没改写的hashcode值也可能不同。所以违背了第二条约定。又如new一个对象,再new一个内容相等的对象,调用equals方法返回的true,但他们的hashcode值不同,将两个对象存入HashSet中,会使得其中包含两个相等的对象,因为是先检索hashcode值,不等的情况下才会去比较equals方法的。



4.Hash表数据结构常识:

1.哈希表基于数组。

2.缺点:基于数组的,数组创建后难以扩展。某些哈希表被基本填满时,性能下降得非常严重。

3.没有一种简便得方法可以以任何一种顺序遍历表中数据项。

4.如果不需要有序遍历数据,并且可以提前预测数据量的大小,那么哈希表在速度和易用性方面是无与伦比的。

为什么HashCode对于对象是如此的重要:

一个对象的HashCode就是一个简单的Hash算法的实现,

关系到你的对象在存取是性能的非常重要的关系,

先来看一下,在JAVA中两个重要的数据结构:HashMap和HashTable,

我们只以Hashtable来说明:

在java中,存取数据的性能,一般来说当然是首推数组,但是在数据量稍大的容器选择中,HashTable将有比数组性能更高的查询速度.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值