Java中重写equals方法为什么要重写hashcode方法?

为了搞懂这个,小瑶先帮大家复习一下基本概念~然后再举个例子就可以搞懂了,~~~

hashcode epuals ==

== 与 equals的区别

  • 如果两个引用类型变量使用==运算符,那么比较的是地址,它们分别指向的是否是同一地址的对象。结果一定是false,因为两个对象不可能存放在同一地址处。

  • 要求是两个对象都不是能空值,与空值比较返回false。

  • ==不能实现比较对象的值是否相同。

  • 所有对象都有equals方法,默认是Object类的equals,其结果与==一样。

  • 如果希望比较对象的值相同,必须重写equals方法。

hashCode与equals的区别

Object中的equals:

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

equals 方法要求满足:

  • 自反性 a.equals(a)

  • 对称性 x.equals(y)  y.equals(x)

  • 一致性 x.equals(y)  多次调用结果一致

  • 对于任意非空引用x,x.equals(null) 应该返回false

Object中的hashCode:

public native int hashCode();

它是一个本地方法,它的实现与本地机器有关,这里我们暂且认为他返回的是对象存储的物理位置。

  • 当equals方法被重写时,通常有必要重写hashCode方法,以维护hashCode方法的常规约定:值相同的对象必须有相同的hashCode。

  • object1.equals(object2)为true,hashCode也相同;

  • hashCode不同时,object1.equals(object2)为false;

  • hashCode相同时,object1.equals(object2)不一定为true;

当我们向一个Hash结构的集合中添加某个元素,集合会首先调用hashCode方法,这样就可以直接定位它所存储的位置,若该处没有其他元素,则直接保存。若该处已经有元素存在,就调用equals方法来匹配这两个元素是否相同,相同则不存,不同则链到后面(如果是链地址法)。

先调用hashCode,唯一则存储,不唯一则再调用equals,结果相同则不再存储,结果不同则散列到其他位置。因为hashCode效率更高(仅为一个int值),比较起来更快。

HashMap#put源码

hash是key的hash值,当该hash对应的位置已有元素时会执行以下代码(hashCode相同)

if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k))))
    e = p;

如果equals返回结果相同,则值一定相同,不再存入。

如果重写equals不重写hashCode会怎样

两个值不同的对象的hashCode一定不一样,那么执行equals,结果为true,HashSet或HashMap的键会放入值相同的对象。

话不多说,直接上例子,~~~

首先我们只重写equals()方法

public class Student {

    private String name;
    private  int age;
    private  String QQ;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age &&
                Objects.equals(name, student.name) &&
                Objects.equals(QQ, student.QQ);
    }

看我们的测试类

public class Test {
    public static void main(String[] args) {
        Student student = new Student();
        Student student2 = new Student();
        System.out.println(student.equals(student2));    //true
        System.out.println(student.hashCode());            //356573597
        System.out.println(student2.hashCode());           //1735600054
        HashMap<Student, String> map = new HashMap<>();
        map.put(student,"123");
        map.put(student2,"456");
        System.out.println(map.get(student));
        System.out.println(map.get(student2));

    }
}

依次输出

true
356573597             student 的hashcode值
1735600054            student 2的hashcode值
123
456

是否出现矛盾???
用equals比较说明对象相同,但是在HashMap中却以不同的对象存储(没有重写hascode值,两个hascode值,在他看来就是两个对象)。
到底这两个对象相等不相等????
说明必须重写hashCode()的重要性,

接下来重写重写equals方法和hashCode方法,再比较

public class Student {

    private String name;
    private  int age;
    private  String QQ;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age &&
                Objects.equals(name, student.name) &&
                Objects.equals(QQ, student.QQ);
    }

    @Override
    public int hashCode() {

        return Objects.hash(name, age, QQ);
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        Student student = new Student();
        Student student2 = new Student();
        System.out.println(student.equals(student2));   //true
        System.out.println(student.hashCode());          // 29791
        System.out.println(student2.hashCode());       // 29791
        HashMap<Student, String> map = new HashMap<>();
        map.put(student,"123");
        map.put(student2,"456");
        System.out.println(map.get(student));   //456
        System.out.println(map.get(student2)); //456

    }
}

依次输出

true
29791           //相同的对象
29791
456			  //说明以一个值key存储,相同的值
456

看到这里,同学 你懂了吗?还不懂,可以自己实现一遍代码。

最后

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值