> 文档中心 > Java基础 | 11.toString( )、hashCode( )和equals( ),Objects工具包

Java基础 | 11.toString( )、hashCode( )和equals( ),Objects工具包

文章目录

  • 参考视频
  • 1.Object:所有类的根类(位于最顶层)
    • 1.1. Object.toString()
    • 1.2.Object.hashCode()
    • 1.3.Object.equals(Object)
  • 2.Objects:工具包
    • 2.1.Objects.equals(Object, Object)
    • 2.2.Objects工具类搭配三种重写方法

参考视频

215 - 218

1.Object:所有类的根类(位于最顶层)

Object类是所有类的根类,所有的类在被创建时,会默认继承Object类(extends)

Object类中有两个比较重要的方法:

  • Object.toString( ):返回"类全限定名+对象地址"
  • Object.hashCode( ):返回"对象的hash值"
  • Object.equals(Object):判断两个对象的地址是否相同,返回布尔值

通常在创建一个类之后,都需要重写这三个方法

1.1. Object.toString()

该方法返回对象对应的"类全限定名 + 对象地址"

Java基础 | 11.toString( )、hashCode( )和equals( ),Objects工具包

重写toString()方法:使其输出对象的成员变量

IDEA可以自动重写toString()方法,alt + Ins一起按,弹出窗口

Java基础 | 11.toString( )、hashCode( )和equals( ),Objects工具包

重写完毕的代码结构如下(参考):

@Overridepublic String toString() {    return "Student{" + "name='" + name + '\'' + ", sex=" + sex + '}';}

1.2.Object.hashCode()

该方法返回"对象的hash值",不同的对象有着不同的地址,因此哪怕成员变量值相等,Object.hashCode()的返回值仍在一般情况下不相同(小概率会相同)

Java基础 | 11.toString( )、hashCode( )和equals( ),Objects工具包

重写hashCode()方法:使成员变量值相等的对象拥有相等的hash值

IDEA可自动重写,重写完毕后代码如下:

@Overridepublic int hashCode() {    return Objects.hash(name, sex);}

这里调用了Objects工具类的hash方法,该方法依照传入的参数值来计算并返回hash值,使得不同对象只要拥有相同的变量值,就判断其hash值相等

特别注意:在重写hashCode( )方法后,hash相同并不代表两个对象相等:

  1. 首先计算时,不同的值有可能计算出相同的hash;

  2. 有可能出现:不同类的对象,恰好其传入的参数值相等,结果显示不同类的对象却拥有相同的hash值

    Java基础 | 11.toString( )、hashCode( )和equals( ),Objects工具包

1.3.Object.equals(Object)

该方法会判断两个对象的地址是否相同,并返回布尔值

该方法的源码非常简单粗暴:

Java基础 | 11.toString( )、hashCode( )和equals( ),Objects工具包

因而,尽管两个对象类型一致,成员变量值也一致,但由于地址不同,最终判定的结果仍然为false

Java基础 | 11.toString( )、hashCode( )和equals( ),Objects工具包

重写equals(Object)方法,使类型一致且成员变量值相等的对象判定为true

IDEA可自动重写,重写完毕后代码如下:

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

可以看到,重写后的判断逻辑如下

  1. 若地址一致时,直接返回true,否则进入下一步
  2. 若传入参数为空,返回false;通过反射判断类型,若类型不同,返回false。若二者都不是,进入下一步
  3. 将传入的对象向下转型(目的是为了使用子类对象的成员变量)
  4. 逐个比较两个对象的所有成员变量,若都相同,返回true,否则返回false

特别注意:若调用者(本对象)为空,尝试调用equals(Object)就会报NPE

而Objects工具包很好地解决了这个问题:

但前提是必须先重写类的equals(Object)方法,详细见下:

2.Objects:工具包

  • Objects.toString(Object):有效避免NPE
  • Objects.hash(Object…):根据传入的值计算hash值
  • Objects.equals(Object, Object):有效避免NPE

2.1.Objects.equals(Object, Object)

Java基础 | 11.toString( )、hashCode( )和equals( ),Objects工具包

相当于:

// 判断地址是否相同,这里包括了a和b同时为null的情况if (a == b){    return true;}// 地址不同时else{    // 若a不为空,进一步判断    if (a != null){ // 调用a.equals(b),如果有重写,将调用重写方法 if(a.equals(b)){     return true; } else{     return false; }    }    // 若a为空,直接返回false    else{ return false;    }}
  1. 先判断地址(这里包括了二者为空的情况)
  2. 再判断a是否为空
  3. 调用a.equals(b)判断(会调用重写方法)

因此在使用Objects.equals(Object, Object)之前,必须要先重写目标类的equals(Object)方法

2.2.Objects工具类搭配三种重写方法

StudentWithOverride.java

package com.xyx_eshang.entity;import java.util.Objects;/ * @author xyx-Eshang */public class StudentWithOverride {    private String name;    private Boolean sex;    @Override    public boolean equals(Object o) { if (this == o) {     return true; } if (o == null || getClass() != o.getClass()) {     return false; } StudentWithOverride student = (StudentWithOverride) o; return Objects.equals(name, student.name) &&     Objects.equals(sex, student.sex);    }    @Override    public int hashCode() { return Objects.hash(name, sex);    }    @Override    public String toString() { return "StudentWithOverride{" +     "name='" + name + '\'' +     ", sex=" + sex +     '}';    }    public String getName() { return name;    }    public StudentWithOverride setName(String name) { this.name = name; return this;    }    public Boolean getSex() { return sex;    }    public StudentWithOverride setSex(Boolean sex) { this.sex = sex; return this;    }}

App.java

package com.xyx_eshang;import com.xyx_eshang.entity.StudentWithOverride;import java.util.Objects;/ * Hello world! */public class App {    public static void testObjectsAndOverride() { StudentWithOverride student1 = new StudentWithOverride().setName("小明").setSex(true); StudentWithOverride student2 = new StudentWithOverride().setName("小明").setSex(true); StudentWithOverride student3 = new StudentWithOverride().setName("小红").setSex(false); StudentWithOverride student4 = null; StudentWithOverride student5 = null; // 1. 重写toString后: System.out.println("Objects.toString(student1):" + Objects.toString(student1)); System.out.println("Objects.toString(student2):" + Objects.toString(student2)); System.out.println("Objects.toString(student3):" + Objects.toString(student3)); System.out.println("Objects.toString(student4):" + Objects.toString(student4)); System.out.println("Objects.toString(student5):" + Objects.toString(student5)); // 2. 重写hashCode后: System.out.println("Objects.hashCode(student1):" + Objects.hashCode(student1)); System.out.println("Objects.hashCode(student2):" + Objects.hashCode(student2)); System.out.println("Objects.hashCode(student3):" + Objects.hashCode(student3)); System.out.println("Objects.hashCode(student4):" + Objects.hashCode(student4)); System.out.println("Objects.hashCode(student5):" + Objects.hashCode(student5)); // 3. 重写equals后,当成员变量值相等,直接调用Object.equals(): System.out.println("student1.equals(student2):" + student1.equals(student2)); // 4. 重写equals后,当成员变量值相等,调用Objects.equals(Object, Object): System.out.println("Objects.equals(student1, student2):" + Objects.equals(student1, student2));    }    public static void main(String[] args) { testObjectsAndOverride();    }}

运行结果如下:

Java基础 | 11.toString( )、hashCode( )和equals( ),Objects工具包