在 java 中有个很特殊的类 Object,它是 所有类的根类。也是唯一一个要求 java 开发人员掌握其所有方法的一个类。对于任何一个类,哪怕我们没有主动写 extends 也会自动继承 Object。根据类的继承层次结构,它的属性和方法会被子子孙孙无条件继承下去,它的方法会被所有类拥有。

在这个层面上来说,object 中的方法一定都是共用性最强的方法,是任何一个对象都应该所拥有的方法。打开 java.lang.Object 类的文件查看可以发现 Object 类里定义的方法其中包括:

  1. equals():判断两个对象是否相等
  2. toString():返回对象的字符串描述
  3. finalize():对象的销毁方法
  4. hashcode():返回哈希值
  5. getClass():获得类模版对象
  6. clone():克隆,它是4种获取对象的方式之一
  7. notify():唤醒线程
  8. notifyAll():唤醒所有线程
  9. wait():共有3个,让线程等待

目前我们只讨论前 3 个方法。

equals()

在进行基本数据类型比较时使用 == 来进行比较,而引用数据类型在进行比较时,比较的是引用,看引用有没有指向同一个对象。
还有一种更常见的情况是需要判断两个对象中的内容是否相等,比如说当搜查犯罪嫌疑人,会以身份证号作为判断依据,在日常生活的认知上我们会认为身份证号相同那就是同一个人,这就是可以安排给 equals() 要做的事儿了:判断两个对象内容是否相等。

  1. // java 所定义的 equals
  2. public boolean equals(Object obj){
  3. return (this == obj)
  4. }

image-20220512152417324.png
equals() 设计出来就是让开发者去重写的,当年 java 在设计 Object 类时并不知道后续的开发人员会写啥样的子类,所以他们只能进行规范:

  1. 既然所有对象都可能相互比较内容,为了避免后续开发者各自去自定义函数,他们固定了函数名去规范这个行为,就指定为 equals
  2. 由于比较的规则是由项目需求规则确定的,所以 java 暂时先写定一个 “==” 去比较,看看内存地址是否相同。但实际项目中具体要比什么,就交给子类的开发人员自己对方法进行 重写 ```java // Student.java 只保留了关键代码 public boolean equals(Object obj) { Student other = (Student) obj; // 数据类型强制转换 // 判断如果姓名年龄相等即为相等 if (other.name.equals(this.name) && other.gender.equals(this.gender)) {
    1. return true;
    } return false; } // TestMain.java Student zhangsan = new Student(“zhangsan”, 18, “male”); Student lisi = new Student(“lisi”, 18, “male”);

boolean result1 = zhangsan.equals(zhangsan); System.out.println(result1 ? “同一个人” : “不是一个人”); // 同一个人

boolean result2 = zhangsan.equals(lisi); System.out.println(result2 ? “同一个人” : “不是一个人”); // 不是一个人

  1. <a name="AEDUm"></a>
  2. # toString()
  3. 首先解除一个误会,java 中的 `toString()` 跟 js 的不同,不是转为字符串。而是返回一个对象的字符串描述。
  4. ```java
  5. // java 中定义的 toString()
  6. public String toString() {
  7. return getClass().getName() + "@" + Integer.toHexString(hashCode());
  8. }
  1. // 打印一个对象
  2. System.out.println(new Parent()); // extend.Parent@f6f4d33
  3. System.out.println(new Child()); // extend.Child@23fc625e

打印一个对象,实际上是自动调用了 toString() ,打印出一串内存中的唯一编号,它返回的是形如 “类的限定名@16进制哈希值”:

  • 类的限定名:该对象是属于哪种数据类型
  • 16进制的哈希值:可以看作是对象的引用,即对象所在的位置
  • 整合起来就是“某类型在某位置的对象”

在自定类型中通常我们更需要看到更详细的自定义格式的对象描述,同样可以重写 toString():

  1. // Student.java 只保留了关键代码
  2. public String toString() {
  3. return "姓名:" + this.name + ",年龄:" + this.age + ",性别:" + this.gender;
  4. }
  5. // TestMain.java
  6. Student zhangsan = new Student("zhangsan", 18, "male");
  7. // 直接打印对象变量
  8. System.out.println(zhangsan); // 姓名:zhangsan,年龄:18,性别:male

在打印对象变量本身时就会自动调用 toString() 。

finalize()

诶?这个标题字体的 “i” 字怎么少一个点…?看起来好奇怪噢嘿嘿
我们已经学习过了使用 new + 构造来产生对象,当对象使用完毕后,Object 类中已经写好的销毁对象方法 finalize() 就会被 GC 根据自身算法自动调用,一般不会需要我们去重写,更不需要去调用。