hashCode与equals的不解之缘

前言

之前学习java核心技术的时候有一节是将hashCode和equals的,在我的印象里面,hashCode是返回对象的内存地址的,equals方法重写的时候,hashCode方法也要重写,认识的程度也仅限于此,前两天学习集合普遍用到hashCode,回来再好好学学,这个还是比较重要的

HashCode

为什么要用hashCode?查一下官方文档

hashcode方法返回该对象的哈希码值。支持该方法是为哈希表提供一些优点,例如,java.util.Hashtable 提供的哈希表。 

hashCode 的常规协定是:
在 Java 应用程序执行期间,在同一对象上多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals 比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。 
如果根据 equals(Object) 方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。 
以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用 hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。 
实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。) 

当equals方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码

我们可以总结以下几小点作用:

  • hashCode存在的意义是为了hash表查找的快速,经过之前的HashMap的源码我们可以看出,hashCode是计算index的必备,但是它也仅仅是计算出index,在发生碰撞的情况下,hashCode相等没错,但是它们的对象不一定是同一个啊!所以说,事实上,hashCode并不是指向真正的地址!有没有?只是index罢了

  • 两个对象相同,equals会相同True,它们的hashcode也要相同,equals重写的时候,hashcode也要重写

  • hashCode相同,不代表对象相同!只是代表index相同,都在一个桶里面

举个简单的例子,说明hash查找法的强大

hashCode的宗旨还在于查找
  在我们学习的初期,最基本的查找算法是什么?你可能会说二分法,一个一个的找对吧,然后去和存储的内容去比对,这一个一个地找下来,对比下来那消耗肯定非常巨大了,如果用上hash,比如HashMap中的查找,我通过hash运算找到index,桶的位置然后再用equals进行对比查找。
  个人感觉我见过的类里面好多都有HashCode这个方法啊- -它具体实现,这个就没必要看了

equals

从Object说起

1、Object.equals

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

Object 用的是==比的是内存地址

2、Objects.equals

    public static boolean equals(Object a, Object b) {
        return (a == b) || (a != null && a.equals(b));
    }

Objects.equals比的是地址和两个对象equals返回的值

3、String.equals

    public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String aString = (String)anObject;
            if (coder() == aString.coder()) {
                return isLatin1() ? StringLatin1.equals(value, aString.value)
                                  : StringUTF16.equals(value, aString.value);
            }
        }
        return false;
    }

我们通过查看String来看看实际中的equals重写,我们可以得出equals几步走

1、判断是否是同一引用(同一对象)
2、根据自己需要判断是instanceof 还是getClass
3、类型强制转换
4、制定自己的比较策略

String的比较 策略是,字节码的一一对比,先判断编码,然后编码的对比

    @HotSpotIntrinsicCandidate
    public static boolean equals(byte[] value, byte[] other) {
        if (value.length == other.length) {
            for (int i = 0; i < value.length; i++) {
                if (value[i] != other[i]) {
                    return false;
                }
            }
            return true;
        }
        return false;
    }

两个值的字节数组的一一对比。

不得不提的一点,getClass还是instanceof

至于使用instanceof 还是getClass,是要根据实际情况看的,当你实际中忽视子类和父类的区别的时候可以用instanceof,但是如果父类和子类是有区别的,比如员工和经理,员工和经理之间进行显然是不合适的,请看下面的例子

package compare;

import java.util.Objects;


public class Employee implements Comparable<Employee>
{
    private String name;
    private double salary;

    public Employee(String name, double salary)
    {
        this.name = name;
        this.salary = salary;
    }

    public String getName()
    {
        return this.name;
    }

    public double getSalary()
    {
        return this.salary;
    }

    @Override
    public boolean equals(Object otherObject)
    {
        if (otherObject == null) 
        {
            return false;
        }

        if (this == otherObject) 
        {
            return true;
        }

        if (this.getClass() != otherObject.getClass()) 
        {
            return false;
        }

        Employee other= (Employee) otherObject;

        return this.getSalary() == other.getSalary()
                && Objects.equals(getName(), getName());
    }

    @Override
    public int hashCode()
    {
        return Objects.hash(this.name,this.salary);
    }

    @Override
    public String toString()
    {
        return getClass().getName() + "[ name: "+this.getName() + ", salary: " + this.getSalary() + " ]"; 
    }   
}

这里的员工的比较对象必须是另外一个员工才行,同时hashcode也要重写,用name和salary作为参数,保证equals相等,hashcode也是相等的

总结

总的来说,hashCode在散列表中的查找起着重要的作用,而equals的重写在于自己制定策略来比较两个对象的相等性,只有真正看过源码,才能知道它们真正的作用,java的hashcode不是内存地址!!!!!- -记住哦

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

河海哥yyds

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值