Java基础 | 11.toString( )、hashCode( )和equals( ),Objects工具包
文章目录
- 参考视频
- 1.Object:所有类的根类(位于最顶层)
-
- 1.1. Object.toString()
- 1.2.Object.hashCode()
- 1.3.Object.equals(Object)
- 2.Objects:工具包
参考视频
215 - 218
1.Object:所有类的根类(位于最顶层)
Object类是所有类的根类,所有的类在被创建时,会默认继承Object类(extends)
Object类中有两个比较重要的方法:
- Object.toString( ):返回"类全限定名+对象地址"
- Object.hashCode( ):返回"对象的hash值"
- Object.equals(Object):判断两个对象的地址是否相同,返回布尔值
通常在创建一个类之后,都需要重写这三个方法
1.1. Object.toString()
该方法返回对象对应的"类全限定名 + 对象地址"
重写toString()方法:使其输出对象的成员变量
IDEA可以自动重写toString()方法,alt + Ins
一起按,弹出窗口
重写完毕的代码结构如下(参考):
@Overridepublic String toString() { return "Student{" + "name='" + name + '\'' + ", sex=" + sex + '}';}
1.2.Object.hashCode()
该方法返回"对象的hash值",不同的对象有着不同的地址,因此哪怕成员变量值相等,Object.hashCode()的返回值仍在一般情况下不相同(小概率会相同)
重写hashCode()方法:使成员变量值相等的对象拥有相等的hash值
IDEA可自动重写,重写完毕后代码如下:
@Overridepublic int hashCode() { return Objects.hash(name, sex);}
这里调用了Objects工具类的hash方法,该方法依照传入的参数值来计算并返回hash值,使得不同对象只要拥有相同的变量值,就判断其hash值相等
特别注意:在重写hashCode( )方法后,hash相同并不代表两个对象相等:
-
首先计算时,不同的值有可能计算出相同的hash;
-
有可能出现:不同类的对象,恰好其传入的参数值相等,结果显示不同类的对象却拥有相同的hash值
1.3.Object.equals(Object)
该方法会判断两个对象的地址是否相同,并返回布尔值
该方法的源码非常简单粗暴:
因而,尽管两个对象类型一致,成员变量值也一致,但由于地址不同,最终判定的结果仍然为false
重写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);}
可以看到,重写后的判断逻辑如下
- 若地址一致时,直接返回true,否则进入下一步
- 若传入参数为空,返回false;通过反射判断类型,若类型不同,返回false。若二者都不是,进入下一步
- 将传入的对象向下转型(目的是为了使用子类对象的成员变量)
- 逐个比较两个对象的所有成员变量,若都相同,返回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)
相当于:
// 判断地址是否相同,这里包括了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; }}
- 先判断地址(这里包括了二者为空的情况)
- 再判断a是否为空
- 调用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(); }}
运行结果如下: