1、根父类:类 Object 是类层次结构的根类。
- (1)超类
- ①每个类都使用 Object 作为超类。
- ②如果一个类没有显式的extends其他类,那么它的父类就是Object。
- ③ 所有对象的创建,最终都会调用Object的无参构造。
- (2)方法
- ①所有对象(包括数组)都实现这个类的方法。
- ②Object类中声明的方法,所有对象都有。
- (3)类型
- ①Object类型的变量可以接收任意类型的对象;
- ②Object类型的数组可以存储任意类型的对象。
2、 Object类的常用方法
(object类一共有11个方法,此处我们先介绍5个基础的)
-
(1)public String toString(): 返回对象的详细信息。
- A:如果我们在打印一个对象,或用对象与字符串进行拼接时,那么会自动调用这个对象的toString()
- B:如果一个类没有编写toString(),会从Object类继承,默认继承的方法实现为: 对象的运行时类型 @ 对象的hashCode码的十六进制形式
- toString()结果应是一个简明但易于读懂的信息表达式。建议所有子类都重写此方法。
int[] arr = {1,2,3}; arr.toString();
* 如果不重写会输出[I@4554617c * 其中[代表是一维数组,I代表是int类型,@,后面的是哈希码
-
(2)public final Class<?> getClass() : 返回此 Object 的运行时类。
- 什么是运行时类?
- 例如我们有一个类为Student,该类继承了Person类
Person p = new Woman(); System.out.println(p.getClass());
- 此时的输出结果为:class 包名.Woman (代表p的运行时类型为Woman)
- 什么是运行时类?
-
(3)protected void finalize(): 垃圾回收
- 当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
- ==>(1)不是程序员手动调用(2)它在对象被GC回收之前调用,类似于临终遗言,满足你最后一个愿望。
- 子类重写 finalize 方法,以配置系统资源或执行其他清除。
- ==>一般资源对象,连接对象才会重写这个方法,用于彻底释放资源用
- 深层次的回答:
- 这个方法可能会导致对象“复活”。如果对象“复活”后,再次成为垃圾后,不会再调用这个finalize()。
- 而且这个方法在程序中无法精确控制它的调用情况(你调用了该方法他也不一定会立马回收,GC有自己的判断方法,如果GC当前很忙,可能暂时不会理会你的调用)。
- 当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
-
(4)public int hashCode(): 返回该对象的哈希码值
-
支持此方法是为了提高哈希表的性能。 ==>当你用到hash算法时,这个hashCode值才会有意义。
-
理想状态下,hashCode是唯一代表一个对象用的一个数字,即希望每一个不同的对象的hashCode值都是唯一的。
-
现实中,不能保证每一个不同的对象的hashCode值不重复的。
-
hashCode 的常规协定:
- A:如果参与计算hashCode值的属性值没有修改,那么hashCode不应该变。
- B:如果调用equals方法判断两个对象“相等”了,那么它俩的hashCode必须一样。
- C:如果两个对象“不相等”,那么它俩的hashCode值可能一样也可能不一样。
-
-
(5)public boolean equals(Object obj): 判断两个对象是否“相等”
- ==:比较的是两个对象的内存地址。只要是分别new的,一定不相等。
- Object类中声明的equals方法,也是比较两个对象的地址,等价于==。
- 所以如果你自己定义的某个类型的对象,调用equals方法时,不想比较地址,那么就要进行重写。
- 重写equals是有要求:
- A:必须和hashCode方法一起重写。选择比较和生成hashCode值的属性是一样
- B:还要遵循几个原则
- ①自反性:x.equals(x)一定是true
- ②对称性:x.equals(y)和y.equals(x)结果是一样
- ③传递性:x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)也是true
- ④一致性:如果参与equals比较的对象的属性值没有修改,那么无论什么时候调用,结果应该一致。
- ⑤一个非空对象与空对象比较,永远是false
hashCode()与equals()方法的重写
class Student{
private String name;
private int score;
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + score;
return result;
}
public boolean equals(Object obj) {
//当前对象,就是equals方法.前面的对象
//System.out.println(s1.equals(s2)); 当前对象是s1, obj是s2 s2实参给形参obj赋值后,发生向上转型
//当前对象如果与obj对象的地址一样,说明是自己和自己必须,返回true
if (this == obj)
return true;
//当前对象非空(如果当前对象为空,则无法调用equals方法,编译会报错),与一个空对象比较,返回false
if (obj == null)
return false;
//当前对象的运行时类型与obj对象的运行时类型不一样,返回false
//if(this.getClass() != obj.getClass())
if (getClass() != obj.getClass())
return false;
//把obj向下转型为Student
//这里向下转型的目的是为了调用学生对象s2中的name和age
//这里为什么没有加instanceof判断,因为上面一行代码表示如果obj不是Student类型,那么就返回false结束了
Student other = (Student) obj;
//如果当前对象的name为null
if (name == null) {
//判断other对象的name是否为null
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
//score是基本数据类型,直接用等号比较就行
if (score != other.score)
return false;
//如果以上的比较都没有出现false,那么说明这两个对象是相等的
return true;
}
}