如何重写Java中的equals方法

Java中,只有8种基本类型不是对象,例如:4种整形类型(byte, short, int,long),2种浮点类型(flout, double),boolean, char不是对象,其他的所有类型,不论是对象数组,列表等都扩展了Object类.了解学习Object中方法的设计原理和实现方式有助于更好的学习理解java语言.下面,我们首先学习一下Object中的equals方法. 判断两个对象相等时,JVM首先查找两个对象的hashCode, 如果两者hashCode不同,则返回false;如果两者的hashCode相同,则调用equals方法进行比较.

Object中equals方法

Object中的equals方法用于检测一个对象是否等于另外一个对象. Object类中,判断两个对象是否引用同一个对象实现equals方法,源码如下:

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

实际处理中,若要比较两个对象是否相等,一般需要重写equals方法.

例1:雇员对象比较

如果两个雇员对象的姓名, 薪水和雇佣一样,就认为它们相等.重写equals方法如下:

public class Employee {

private String name;
    private double salary;
    private Date hireDay;

...

@Override
    public boolean equals(Object obj) {
        // 如果为同一对象的不同引用,则相同
        if (this == obj) {
            return true;
        }
        // 如果传入的对象为空,则返回false
        if (obj == null) {
            return false;
        }

// 如果两者属于不同的类型,不能相等
        if (getClass() != obj.getClass()) {
            return false;
        }

// 类型相同, 比较内容是否相同
        Employee other = (Employee) obj;

return Objects.equals(name, other.name) && salary == other.salary && Objects.equals(hireDay, other.hireDay);
    }
}

注意,比较通过Objects中静态函数equals比较两个对象是否相等.该方法源码如下:

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

这样,当两个对象都为null时,返回true,例如,两个Employee对象的name都为null, 返回true; 如果第一个对象不为null,则调用a.equals(Object obj)方法

对象比较与继承

如果隐式和显式的对象所属类型不一致,equals方法该如何处理呢?在例1中,如果两个对象的类型不一致,直接返回false;多数程序员直接使用instanceof检测:

if(!(obj instanceof Employee)) return false;

这样做不但没有解决继承子类的错误,还可能引发其他的一些错误,例1中,采用强制类型转换的方式.

要实现子类对象比较,先了解一下java规范中对equals方法的约束.

java规范中equals方法特征

  • 自反性

对于任何非空引用x, x.equals(x) 返回true;

  • 对称性

对于任何引用x, y, 当且仅当y.equals(x) 返回true, x.equals(y)返回true;

  • 传递性

对于任何引用x, y, z, 若x.equals(y)返回true, y.equals(z)返回true; 则 x.equals(z)返回true;

  • 一致性

若x和y引用的对象没有发生改变, 则反复调用x.equals(y)应该返回同样的结果.

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

下面可以通过两个不同的情况看待这个问题:

  • 如果子类能够拥有自己的相等概念, 则对称性需求强制采用getClass进行检测
  • 如果由超类决定相等的概念, 那么就用instanceof进行检测,这样可以在不用子类的对象之间进行相等的比较

注释:

  1. 在标准的java库中包含150多个equals方法的实现,包括instanceof检测, 调用getClass检测, 捕获ClassCastException检测或者什么都不做. 在java.sql.TimeStamp实现人员指出, Timestamp类继承Date类,而后者的equals方法使用了一个instanceof检测,这样重写equals方法时,就无法同时做到对称性.
  2. 在由超类决定相等时,可以考虑final关键字修改比较函数,若考虑到子类equals方法灵活性,可以不加修饰,例如AbstractSet.equals方法,应该申明为final, 这样就可以比较子类HashSet和TreeSet, 但是考虑到子类的灵活性,没有添加任何修饰.

编写equals方法的建议:

  1. 显示参数命名为otherObject, 稍后转化成other变量

    public boolean equals(Object otherObject)

  2. 检测this和otherObject是否是同一个对象的引用,是,返回true;

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

  3. 检测otherObject是否为null, 是, 返回false;

    if(otherObject == null){
        return false;
    }

  4. 比较this和otherObject是否属于同一个类. 如果equals的语义在每个子类中有所改变,就使用getClass检测:

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

    如果所以子类语义相同,使用instanceof检测:

    if(!(otherObject instanceof Employee)){
        return false;
    }

  5. 将otherObject转化为相对应的类型变量other

    Employee other = (Employee)otherObject;

  6. 对所需要的比较的数据域进行比较. 如果是基本数据类型,使用a==b比较; 如果是对象比较,调用Objects.equals(a, b)进行比较

    return Objects.equals(name, other.name) && salary == other.salary && Objects.equals(hireDay, other.hireDay);

整个流程可以参照例1;

常见equals方法实现错误

public class Employee {
    public boolean equals(Employee other) {

return Objects.equals(name, other.name) && salary ==other.salary && Objects.equals(hireDay, other.hireDay);
}

这个方法声明的显示参数类型是Employee. 其结果并没有覆盖Object中的equals方法,而是定义了一个完全无关的方法.为了避免发生类型错误,可以使用@override对覆盖超类的方法进行标记.

---恢复内容结束---

时间: 2024-12-17 15:53:14

如何重写Java中的equals方法的相关文章

java中‘==’和‘equals()’方法的有趣探索

这两天在看周志明的<深入理解java虚拟机>,受益颇多,根据书中的启示,对java中'=='和'equals()'方法的区别做了一些探索. 首先,为了更快地让进入状态,我们先来所几个判断题,例程如下,请判断各个System.out.println()输出的结果. <pre name="code" class="java"> public static void main(String[] args) { Integer a =1; Integ

【转】彻底弄懂Java中的equals()方法以及与&quot;==&quot;的区别

彻底弄懂Java中的equals()方法以及与"=="的区别 一.问题描述:今天在用Java实现需求的时候,发现equals()和“==”的功能傻傻分不清,导致结果产生巨大的偏差.所以,我决定花费时间把equals()和“==”的功能彻底弄懂,前事不忘后事之师嘛,分享给大家,希望对大家理解equals()和“==”的功能有所帮助. 二.分析探索解决问题的方法:1.Object 中的equals()方法: (1)通过查找API,说明如下: equalspublic boolean equ

Java中“==”与equals方法的区别

1. 用“==”比较两个变量,如果两个变量是基本类型变量,且都是数值类,则值相等就返回true 如果两个变量是引用型变量,则两个对象的地址一样,即指向同一个对象,则返回true 2.equals:String类对equals进行了重写:1)若是同一个对象,返回true: 2)若不是,则比较它们的值,值相同,返回true 重写代码: public boolean equals(Object anObject) { if (this == anObject) { return true; } if

JAVA中复写equals方法

一般说来,所有类都应该复写Object中的equals方法.步骤大概分三步: 1) 判断两个对象地址是否一致 2)判断第二个对象是否为同一个子类实例 3)判断内容是否一致 class Person { public int age; public String name; public Person(int age, String name) { this.age = age; this.name = name; } public boolean equals(Object obj) { //第

java中的equals()方法重写

如何java中默认的equals方法跟实际不符的话,需要重写equals方法.例如: public class TestEquals {public static void main(String[] args) { Cat c1 = new Cat (1,2,3); Cat c2 = new Cat (1,2,3); System.out.println(c1==c2); System.out.println(c1.equals(c2));}} class Cat{ int color ;  

小结下java中==与equals方法

1 public class EqualsTest { 2 3 public static void main(String[] args) { 4 String s1 = "abc"; 5 String s2 = "abc"; 6 String s3 = new String("abc"); 7 String s4 = new String("abc"); 8 9 /* 10 * 首先要明确:==比较的是对象引用,即内存中的

java中的equals()方法

大家都知道,在Java中,对于对象的比较,如果用“==”比较的是对象的引用,而equals才是比较的对象的内容. 一般我们在设计一个类时,需要重写父类的equals方法,在重写这个方法时,需要按照以下几个规则设计: 1.自反性:对任意引用值X,x.equals(x)的返回值一定为true.2.对称性:对于任何引用值x,y,当且仅当y.equals(x)返回值为true时,x.equals(y)的返回值一定为true;3.传递性:如果x.equals(y)=true, y.equals(z)=tr

Java中==和equals方法的分析

原文引用https://www.dazhuanlan.com/2019/08/26/5d62fa816b34b/ 前言 == 和 equals是经久不衰的面试题,记得刚毕业的时候我也被问到过很多次,从最开始的一脸懵逼到最后的从容回答,本文我们就来分析下这两者之间的区别和联系. 为避免阅读疲劳,我这里先放上结论: 联系: 两者都被用来进行比较操作 当equals()未被重写时,两者的用途和比较的内容相同,即都是比较对象的引用地址是否相同 区别: ==既可以比较基本数据类型,亦可用在对象之间.equ

Eclipse4.7使用基础 快捷键 重写子类中的equals方法

os :windows7 x64    jdk:jdk-8u131-windows-x64    ide:Eclipse Oxygen Release (4.7.0) 原先的代码 package jizuiku.eleven302; public class Javaer { private int age; private String name; public int getNum() { return age; } public void setNum(int age) { this.ag