hashCode()与equals()的相关问题

对于hashCode()与equals的相关问题之前我一直是模模糊糊的,问题答案我觉得都有点答非所问。

针对hashCod与equals问题进行整理归纳:
1、equals()的作用是什么?

equals() 的作用是 用来判断两个对象是否相等

equals() 是Object类中的方法。通过判断两个对象的地址是否相等(即,是否是同一个对象)来区分它们是否相等。源码如下:

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

意味着所有的Java类都实现了equals()方法,所有的类都可以通过equals()去比较两个对象是否相等。但它默认使用的“equals()”方法,等价于“==”方法。因此,我们通常会重写equals()方法:当两个对象的内容相等,则equals()方法返回true;否则,返回fasle。  

下面根据“类是否重写了equals()方法”,分为2类:

  1.  若某个类没有覆盖equals()方法,当它的通过equals()比较两个对象时,实际上是比较两个对象是不是同一个对象。这时,等价于通过“==”去比较这两个对象。
  2. 我们可以覆盖类的equals()方法,来让equals()通过其它方式比较两个对象是否相等。通常的做法是:若两个对象的内容相等,则equals()方法返回true;否则,返回fasle。

以自定义User类为例:

public class User {
    private String username;
    private String password;
    //...省略构造方法,getter,setter

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

 情形1:在User类中未重写equals(),创建2个内容完全一样的User对象进行比较

User类中没有对父类的equals()进行重写,那么在调用equlas()时默认会调用Object类中的equals(),在上面我们已经看了Object类中equals()的源码,实际上就是“==”比较对象的内存地址,故两个内容完全一致的User对象进行equals比较时返回的false。

情形2:User类中重写equals(),再次对两个内容一致的User对象进行equals()比较

测试类与情形1一致,需在User类中添加重写的equals() 

在User类中对equals()进行重写,用于判断两个对象的内容是否一样,相同则返回true;重写后User对象在调用equals()时调用的是自己覆盖过的equals(),不再是Object类的方法

2、hashCode()的作用是什么?

hashCode() 的作用是获取哈希码,也称为散列码;它实际上是根据当前对象在内存中的内存地址计算出来的一个int类型的整数。(-2^31~2^31-1)这个哈希码的作用是确定该对象在哈希表中的索引位置。

hashCode() 的定义也在Object类中,同样意味着Java中的任何类都有hashCode() 。
 虽然每个Java类都包含hashCode() ,但仅仅当创建并使用某个“类的散列表(哈希表)”时,该类的hashCode() 才有用(作用是:确定该类的每一个对象在散列表中的位置;其它情况下(例如,创建类的单个对象,或者创建类的对象数组等等),类的hashCode() 没有作用。
散列表,指的是:Java集合中本质是散列表的类(低层是HashMap),如HashMap,Hashtable,HashSet等。

通过往HashSet中添加User对象来举例说明:

若HashSet中以有10个User对象,当添加第11个User对象时会发生什么?不会挨个比较

(1)根据当前User对象的hashCode()计算出在散列表中的位置并插入

(2)对于"相同"(内容)的User对象只添加一次

3、hashCode()和equals()的联系?

老听见一句话“重写equals()时一定要重写hashCode()”,但这句话是有条件的,并非所有重写equals()的情况下都需要对hashCode()进行重写。

在上面对于hashCode()作用的理解中,也说了它是在对于有对应类的散列表时是起“作用”的(通过hashCode()查找当前对象存储在散列表中的位置)。我们往HashSet中添加User对象,以重写hashCode()和不重写hashCode()进行对照的形式来理解。

User类的代码不在赘述,同上

 情形1:只重写了equals()未重写hashCode()

只重写equals(),在往Set集合中添加元素时,它首先会通过当前对象的hashCode()计算出在哈希表中的位置,若当前位置还没有元素,它会认为当前集合中的元素没重复,可以添加进来。但对于我们的需求来讲,对于u1,u2对象往Set集合中添加时只能添加一个。对于两个User对象,未重写hashCode(),那么它们的hashCode()默认调用父类的,则是通过对象的内存地址计算出的一个int整数值,相同的User对象hashCode一定相同,不同的对象hashCode()“大概率”不相同(hashCode为int整数,有取值范围,存在重复可能性)。

故在往散列表集合中添加对象时,若对于相同内容的对象不想重复添加时,我们在重写equals()的同时也需要重写hashCode()。

情形2:重写equals()同时也重新了hashCode()

 

我们通过User对象的两个属性的hashCode做位运算重写了hashCode()后,对于两个内容相同的不同对象所计算出的hashCode是相同的,那么在往Set集合中添加User对象时,两个对象在散列表中的存储位置是一样的,添加u2时当前位置已有元素,就不会添加成功了,达到去重的效果。

小结:

  •         往散列表集合中添加对象,需同时重写equals()和hashCode()
  •         两个相同的对象,它们的hashCode()一定相等
  •         两个对象的hashCode()相等,这两个对象不一定相等
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值