Java基础深度总结:Object类-equals方法

现在的我不配喊累,因为我一无所有。

1.equals概述

Object类的equals方法用“==”来比较两个对象,因此它的含义是两个对象是否一样,这里的一样指它们是否为同一个对象。

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

== 与 equals

  • ‘==’ 与 equals 最大的区别是: == 是运算符 而 equals 是方法。
  • ‘==’ 可以用于基本类型,表示它们的值是否相等,也可以用于引用类型,表示比较的是对象的地址值是否相等;而equals只能用于比较两个对象。
  • 如果没有重写equals方法,也就是说该方法是从超类Object继承而来的,那么equals 与 ‘==’ 是完全等价的,都比较的是对象的内存地址。
  • 使其按照实际的需求实现的equals方法主要用于判断对象是否等价,也就是说两个对象是逻辑相等的,而不会去关心他们是否为同一个对象的引用。
Integer x = new Integer(1);
Integer y = new Integer(1);
System.out.println(x.equals(y)); // true
System.out.println(x == y);      // false
2.何时才要覆盖equals方法

很多情况下我们都不必去覆盖equals方法:

  • 类的每个实例本质上都是唯一的。如Thread。
  • 超类已经覆盖equals方法了,并且从超类继承来的行为对子类也是合适的。
  • 不关心类是否提供了“逻辑相等”的测试功能。
  • 确定这个类的equals方法永远不会被调用时。

而当一个类需要自己的特有的“逻辑相等”概念,并且逻辑相等不等同于对象相等时,我们就不得不去覆盖Object类的equals方法。例如我们希望两个实例的某些关键域相等时,我们就认为它们两者是逻辑上相等的,如果不覆盖equals方法,继承Object类的equals方法,那么一个实例只能和它自身相等。

3.覆盖equals的通约

一个正确的equals方法的实现,应该满足等价关系。等价关系包含以下几个方面:

  • 自反性:对于任何非null的引用值x,x.equals(x)应返回true。
  • 对称性:对于任何非null的引用值x与y,当且仅当:y.equals(x)返回true时,x.equals(y)才返回true。
  • 传递性:对于任何非null的引用值x、y与z,如果y.equals(x)返回true,y.equals(z)返回true,那么x.equals(z)也应返回true。
  • 一致性:对于任何非null的引用值x与y,若对象上equals比较中的信息没有被修改,则多次调用x.equals(y)就会一致地返回true或false。
  • 非空性:对于任何非空引用值x,x.equal(null)应返回false。

结合这些要求,以下就是实现高质量equals方法:

  • 检查是否为同一个对象的引用,如果是直接返回 true;
  • 检查是否是同一个类型,如果不是,直接返回 false;
  • 将 Object 对象进行转型;
  • 判断每个关键域是否相等。
4.重写equals()中的getClass与instanceof

重写equals()方法,检查是否是同一个类型时。用getClass好呢还是instanceof好?我们推荐使用getClass。

instanceof可以判断其左边对象是否为其右边类的实例,返回 boolean 类型的数据。

public class EqualsWithExtendsTest {


    public static void main(String[] args) {
        Employee e1 = new Employee(1,"张三");
        People p1 = new People("张三");
        System.out.println("e1.equals(p1):" + e1.equals(p1) + "---p1.equals(e1):" + p1.equals(e1));
    }

}

class People{

    private String name;

    public People(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof People)) return false;

        People people = (People) o;

        return name != null ? name.equals(people.name) : people.name == null;
    }
}

class Employee extends People {
    private int id;

    public Employee(int id,String name) {
        super(name);
        this.id = id;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Employee)) return false;
        if (!super.equals(o)) return false;

        Employee employee = (Employee) o;

        return id == employee.id;
    }

}
输出:
e1.equals(p1):false---p1.equals(e1):true

解析:
显然,存在继承关系时,在equals方法中使用instanceof违反了equals通约的对称性,这是由于Employee 类的对象可以识别出People对象,但是People识别不出Employee 的对象,也就是 Employee 对象 instanceof People对象 为true,而People对象 instanceof Employee 对象 为 false,所以导致不遵循对称性原则。

解决上述问题可以用组合代替继承:

class EmployeeNew{

    private int id;
    private People people;

     public EmployeeNew(int id, People people) {
        this.id = id;
        this.people = people;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof EmployeeNew)) return false;

        EmployeeNew that = (EmployeeNew) o;

        if (id != that.id) return false;
        return people != null ? people.equals(that.people) : that.people == null;
    }

}

也可以保留继承关系,使用getClass替代 instanceof (推荐),注意使用getClass之前进行非空判断,而instanceof 会帮你非空判断的。

class People{

    private String name;

    public People(String name) {
        this.name = name;
    }

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

        People people = (People) o;

        return name != null ? name.equals(people.name) : people.name == null;
    }

}

class Employee extends People {
    private int id;

    public Employee(int id,String name) {
        super(name);
        this.id = id;
    }

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

        Employee employee = (Employee) o;

        return id == employee.id;
    }

}

Tips:

  • 覆盖equals方法时总要覆盖hashCode方法:Java基础总结:Object类-hashCode方法 中有详细的解释。
  • 不要企图让equals方法过于智能。
  • 不要将equals声明中的Object对象替换为其他的类型。
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值