关于equals的那些事

==和equals的区别是什么?

==比较的是两个对象在内存中的地址,equals比较的是两个对象的值。这个说法是片面的。

==的作用

==是专门用来比较两个变量是否相等的,即比较两个变量在内存中存储的数据值是否相等,比较两个基本数据类型或者两个引用变量是否相等时,只能用==

  • 变量:指可以改变的量,是内存中的一个空间(容器),用于存储数据
  • 引用变量:当一个变量指向的是对象类型的数据,那这个变量即引用变量
//obj为引用变量,存储的数据为new Object()这个对象在内存中的地址,并不是对象的值
Object obj = new Object();

equals的作用

  • Object类中的equals方法在比较是用的还是==,所以如果没有重写equals方法,它将继承Object类中的equals方法,相当于还是在使用==进行比较
    //Object类中的equals方法,是用==进行比较
    public boolean equals(Object obj) {
        return (this == obj);
    }
  • 对于重写过的equals方法,比较的是两个对象的值,如String中的equals方法
    //String源码中的equals方法
    public boolean equals(Object anObject) {
        //先用==比较,如果内存中的地址一样,则不再进行比较,直接返回true
        if (this == anObject) {
            return true;
        }
        //是String类型,才进行以下的比较
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                //通过循环比较字符串中每个字符的值是否相等,不相等则返回false
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        //其他情况则直接返回false
        return false;
    }
  • 对于基本数据类型的包装类,也是重写了equals方法,比较的是对象的值
    //以Integer为例,比较的是对象的值,其他基本数据类型的包装类也一样
    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }
  • 自定义对象,如果重写了equals方法,则比较的是每个属性的值是否相等
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.yms.entity;

public class User {
  private String name;
  private Integer age;

  public User() {
  }

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

  public Integer getAge() {
    return this.age;
  }

  public void setName(final String name) {
    this.name = name;
  }

  public void setAge(final Integer age) {
    this.age = age;
  }

  public boolean equals(final Object o) {
    if (o == this) {
      return true;
    } else if (!(o instanceof User)) {
      return false;
    } else {
      User other = (User)o;
      if (!other.canEqual(this)) {
        return false;
      } else {
        Object this$age = this.getAge();
        Object other$age = other.getAge();
        if (this$age == null) {
          if (other$age != null) {
            return false;
          }
        } else if (!this$age.equals(other$age)) {
          return false;
        }

        Object this$name = this.getName();
        Object other$name = other.getName();
        if (this$name == null) {
          if (other$name != null) {
            return false;
          }
        } else if (!this$name.equals(other$name)) {
          return false;
        }

        return true;
      }
    }
  }

  protected boolean canEqual(final Object other) {
    return other instanceof User;
  }

  public int hashCode() {
    int PRIME = true;
    int result = 1;
    Object $age = this.getAge();
    result = result * 59 + ($age == null ? 43 : $age.hashCode());
    Object $name = this.getName();
    result = result * 59 + ($name == null ? 43 : $name.hashCode());
    return result;
  }

  public String toString() {
    return "User(name=" + this.getName() + ", age=" + this.getAge() + ")";
  }
}

为什么重写了equals方法就必须重写hashCode方法?

  • 在每个覆盖了equals方法的类中,都必须覆盖hashCode方法。如果不这样做的话,就会违反hashCode的通用约定,从而导致该类无法结合所有基于散列的集合一起正常运作,这列集合包括HashMap和HashSet。
  • 如果两个对象的值相等,那么它们对应的hashCode则一定相等,反过来则不一定,这就是我们所说的哈希冲突

对于equals的其他理解可参考Effective Java 第三版中第10条、第11条

        

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值