“equals”与“==”的区别-如何重写equals()和hashCode()方法

Posted hequnwang10

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了“equals”与“==”的区别-如何重写equals()和hashCode()方法相关的知识,希望对你有一定的参考价值。

一、“equals”与“==”的区别

  1. 默认情况下也就是从超类Object继承而来的equals方法与"==“是完全等价的,比较的都是对象的内存地址(quals 比较的是值和地址,如果没有重写equals方法,其作用与”=="相同);
  2. 但我们可以重写equals方法,使其按照我们的需求的方式进行比较,如String类重写了equals方法,使其比较的是字符的序列,而不再是内存地址;
  3. hashCode用于散列数据结构中的hash值计算;
  4. equals两个对象相等,那hashcode一定相等,hashcode相等,不一定是同一个对象;

二、重写equals()和hashCode()方法

  • equals - 保证比较对象是否是绝对相等的
  • hashCode - 保证在最快的时间内判断两个对象是否相等,可能有误差值

1、hashCode()方法

  • hashCode 的存在主要用于查找的快捷性,如 Hashtable, HashMap 等,hashCode 是用来在三列存储结构中确定对象的存储地址的。
  • 如果两个对象相同,就是适用于 euqals(java.lang.Object) 方法,那么这两个对象的 hashCode一定相同。
  • 如果对象的euqals 方法被重写,那么对象的 hashCode 也尽量重写,并且产生 hashCode 使用的对象,一定要和 equals 方法中使用的一致,否则就会违反上面提到的第二点。
  • 两个对象的 hashCode 相同,并不一定表示这两个对象就相同,也就是不一定适用于equals() 方法,只能够说明这两个对象在三列存储结构中,如 Hashtable.,他们存在同一个篮子里。

首先举个例子来看一下equals()的方法的使用

package com.leetcode;

import java.util.Objects;

public class test 
    private int id;

    public int getId() 
        return id;
    

    public void setId(int id) 
        this.id = id;
    

    public test(int id) 
        this.id = id;
    

    public static void main(String[] args) 
        test t1 = new test(1);
        test t2 = new test(1);
        String str1 = "123";
        String str2 = "123";
        String str3 = "124";
        System.out.println("str1地址:"+System.identityHashCode(str1));
        System.out.println("str2地址:"+System.identityHashCode(str2));
        System.out.println("str3地址:"+System.identityHashCode(str3));
        System.out.println("str1.equals(str2)"+str1.equals(str2));
        System.out.println("t1地址:"+System.identityHashCode(t1));
        System.out.println("t2地址:"+System.identityHashCode(t2));
        System.out.println("t1.equals(t2)"+t1.equals(t2));
        System.out.println("t1 == t2"+(t1 == t2));
        System.out.println("t1.hashCode()"+t1.hashCode());
        System.out.println("t2.hashCode()"+t2.hashCode());
    

输出:

str1地址:23934342
str2地址:23934342
str3地址:22307196
str1.equals(str2)true
str1.equals(str3)false
t1地址:10568834
t2地址:21029277
t1.equals(t2)false
t1 == t2false
t1.hashCode()10568834
t2.hashCode()21029277

String类重写了equals方法,使其比较的是字符的序列,而不再是内存地址,所以我们发现str1和str2相等,但和str3不相等;

这里我们并没有重写equals()方法和hashCode()方法,打印t1地址和t2地址是不相等的,他们的hashCode也是不相等的,所以比较t1.equals(t2)时是不相等的。

2、只重写equals()方法

package com.leetcode;

import java.util.Objects;

public class test 
    private int id;

    public int getId() 
        return id;
    

    public void setId(int id) 
        this.id = id;
    

    public test(int id) 
        this.id = id;
    

    @Override
    public boolean equals(Object o) 
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        test test = (test) o;
        return id == test.id;
    

    public static void main(String[] args) 
        test t1 = new test(1);
        test t2 = new test(1);
        System.out.println("t1地址:"+System.identityHashCode(t1));
        System.out.println("t2地址:"+System.identityHashCode(t2));
        System.out.println("t1.equals(t2)"+t1.equals(t2));
        System.out.println("t1 == t2"+(t1 == t2));
        System.out.println("t1.hashCode()"+t1.hashCode());
        System.out.println("t2.hashCode()"+t2.hashCode());
    

输出:

t1地址:23934342
t2地址:22307196
t1.equals(t2)true
t1 == t2false
t1.hashCode()23934342
t2.hashCode()22307196

虽然t1和t2的地址不相等,但是我们重写了equals()方法,使equals为比较两个的id值是否相等,所以比较之后t1.equals(t2)返回true。
但是这里的hashcode不相等,如果只重写equals而不重写HashCode会有什么影响?
两个相等的对象必须具有相等的散列码(Java关键约定

举一个例子:
​如果一个只重写了equals(比较所有属性是否相等)的类 new 出了两个属性相同的对象。这时可以得到的信息是这个
属性相同的对象地址肯定不同,但是equals是true,hashCode返回的是不相等的(一般不会出现hash碰撞)。

也就是说这个类对象违背了Java对于两个对象相等的约定。违背约定的原因是 可靠的equals判断两个对象是相等
的,但是他们两个的散列码确是不相等的。

总结:

  • equals 为 true , hashCode 必须相等
  • hashCode 相等时 , equals 可以不用为 true (也就是hash碰撞的时候)

不写hashCode()的影响:

  • 两个所有属性都相等的对象,但是地址不同。没重写hashCode时,p.hash == hash 一定不相等。但是逻辑上这两个对象是相等的,并且equals也是相等的。
    ​ - 这就会导致,HashMap里面本来有这个key,但是你告诉我没有,导致了put操作成功。逻辑上是不符合规范的,get时取出来的也可能是自己另一个的value。

3、重写equals()方法和hashCode()方法

package com.leetcode;

import java.util.Objects;

public class test 
    private int id;

    public int getId() 
        return id;
    

    public void setId(int id) 
        this.id = id;
    

    public test(int id) 
        this.id = id;
    

    @Override
    public boolean equals(Object o) 
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        test test = (test) o;
        return id == test.id;
    

    @Override
    public int hashCode() 
        return Objects.hash(id);
    

    public static void main(String[] args) 
        test t1 = new test(1);
        test t2 = new test(1);
        System.out.println("t1地址:"+System.identityHashCode(t1));
        System.out.println("t2地址:"+System.identityHashCode(t2));
        System.out.println("t1.equals(t2)"+t1.equals(t2));
        System.out.println("t1 == t2"+(t1 == t2));
        System.out.println("t1.hashCode()"+t1.hashCode());
        System.out.println("t2.hashCode()"+t2.hashCode());
    

输出:

t1地址:23934342
t2地址:22307196
t1.equals(t2)true
t1 == t2false
t1.hashCode()32
t2.hashCode()32

以上是关于“equals”与“==”的区别-如何重写equals()和hashCode()方法的主要内容,如果未能解决你的问题,请参考以下文章

Java面试题QA

== 区别 equals

Java面试宝典常用类中的方法重写|equals方法与逻辑运算符==的区别

java中equals与==号的区别

==与equals的区别

java_StringStringBuilder