在 java 中有个很特殊的类 Object,它是 所有类的根类。也是唯一一个要求 java 开发人员掌握其所有方法的一个类。对于任何一个类,哪怕我们没有主动写 extends 也会自动继承 Object。根据类的继承层次结构,它的属性和方法会被子子孙孙无条件继承下去,它的方法会被所有类拥有。
在这个层面上来说,object 中的方法一定都是共用性最强的方法,是任何一个对象都应该所拥有的方法。打开 java.lang.Object 类的文件查看可以发现 Object 类里定义的方法其中包括:
- equals():判断两个对象是否相等
- toString():返回对象的字符串描述
- finalize():对象的销毁方法
- hashcode():返回哈希值
- getClass():获得类模版对象
- clone():克隆,它是4种获取对象的方式之一
- notify():唤醒线程
- notifyAll():唤醒所有线程
- wait():共有3个,让线程等待
equals()
在进行基本数据类型比较时使用 ==
来进行比较,而引用数据类型在进行比较时,比较的是引用,看引用有没有指向同一个对象。
还有一种更常见的情况是需要判断两个对象中的内容是否相等,比如说当搜查犯罪嫌疑人,会以身份证号作为判断依据,在日常生活的认知上我们会认为身份证号相同那就是同一个人,这就是可以安排给 equals() 要做的事儿了:判断两个对象内容是否相等。
// java 所定义的 equals
public boolean equals(Object obj){
return (this == obj)
}
equals() 设计出来就是让开发者去重写的,当年 java 在设计 Object 类时并不知道后续的开发人员会写啥样的子类,所以他们只能进行规范:
- 既然所有对象都可能相互比较内容,为了避免后续开发者各自去自定义函数,他们固定了函数名去规范这个行为,就指定为 equals
- 由于比较的规则是由项目需求规则确定的,所以 java 暂时先写定一个 “==” 去比较,看看内存地址是否相同。但实际项目中具体要比什么,就交给子类的开发人员自己对方法进行 重写
```java
// Student.java 只保留了关键代码
public boolean equals(Object obj) {
Student other = (Student) obj; // 数据类型强制转换
// 判断如果姓名年龄相等即为相等
if (other.name.equals(this.name) && other.gender.equals(this.gender)) {
} return false; } // TestMain.java Student zhangsan = new Student(“zhangsan”, 18, “male”); Student lisi = new Student(“lisi”, 18, “male”);return true;
boolean result1 = zhangsan.equals(zhangsan); System.out.println(result1 ? “同一个人” : “不是一个人”); // 同一个人
boolean result2 = zhangsan.equals(lisi); System.out.println(result2 ? “同一个人” : “不是一个人”); // 不是一个人
<a name="AEDUm"></a>
# toString()
首先解除一个误会,java 中的 `toString()` 跟 js 的不同,不是转为字符串。而是返回一个对象的字符串描述。
```java
// java 中定义的 toString()
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
// 打印一个对象
System.out.println(new Parent()); // extend.Parent@f6f4d33
System.out.println(new Child()); // extend.Child@23fc625e
打印一个对象,实际上是自动调用了 toString() ,打印出一串内存中的唯一编号,它返回的是形如 “类的限定名@16进制哈希值”:
- 类的限定名:该对象是属于哪种数据类型
- 16进制的哈希值:可以看作是对象的引用,即对象所在的位置
- 整合起来就是“某类型在某位置的对象”
在自定类型中通常我们更需要看到更详细的自定义格式的对象描述,同样可以重写 toString():
// Student.java 只保留了关键代码
public String toString() {
return "姓名:" + this.name + ",年龄:" + this.age + ",性别:" + this.gender;
}
// TestMain.java
Student zhangsan = new Student("zhangsan", 18, "male");
// 直接打印对象变量
System.out.println(zhangsan); // 姓名:zhangsan,年龄:18,性别:male
finalize()
诶?这个标题字体的 “i” 字怎么少一个点…?看起来好奇怪噢嘿嘿
我们已经学习过了使用 new + 构造来产生对象,当对象使用完毕后,Object 类中已经写好的销毁对象方法 finalize() 就会被 GC 根据自身算法自动调用,一般不会需要我们去重写,更不需要去调用。