Java Object类用法详解
Object 是 Java 中所有类的父类,也就是说,Java 中的所有类都具备 Object 类的所有特性。因此,读者有必要掌握 Object 类的用法。
当定义一个类时,如果没有使用关键字 extends 显式指定该类继承的父类,那么编译器自动添加 extends java.lang.Object。也就是说,任何一个类在定义时如果没有明确地继承一个父类,那么它将直接继承 Object 类。因此,可以说 Java 中的每个类都是 Object 类的直接或间接子类。
Object 类中定义了所有的 Java 类经常使用的方法,子类可以直接使用或覆盖后使用。由于 Object 类中定义的方法的逻辑并不一定适用于所有子类,因此大部分子类需要重写从 Object 类继承的方法才能使用。
Object 类的常用方法如下表所示。
下面介绍几个常用的方法。
1) public String toString():返回该对象的字符串表现形式。Object类中定义的默认逻辑是返回对象的类型+@+hashCode值,其中的 hashCode 值默认将对象的内存地址转换为整型表示。
Object 类中 toString() 方法的默认实现如下:
另外,当使用 System.out.print() 方法打印一个对象时,如果该对象的值不为 null,那么底层调用该对象的 toString() 方法,先获取该对象的字符串表现形式,再打印该字符串。
【实例】重写toString()方法。
2) public boolean equals(Object obj):比较某个对象是否与当前对象相等。调用成员方法 equals() 并指定参数为另一个对象,用来判断这两个对象是否是相同的。
这里的“相同”有默认和自定义两种方式。
为了避免造成歧义,在开发过程中一般使用“==”运算符进行对象物理相等的判断,使用 equals() 方法进行对象逻辑相等的判断。
【实例】重写equals()方法。
3) hashCode()方法:返回对象的是哈希码。在一些基于 Hash Table 算法的容器中,需要根据对象的哈希码计算对象在容器中的下标。如果将一个对象存入此类容器中,那么底层会调用该对象的hashCode()方法。
Hash 算法对 hashCode() 方法的实现有如下几点要求:
与 equals() 方法类似,大多数 IDE 可以自动生成 equals() 方法的代码内容,其核心逻辑是基于对象所有参与逻辑相等比较的成员变量的值,经过特定的计算得到一个整数。在这种情况下,若两个对象参与计算的成员变量的值相等,则返回相同的哈希码;若其中一个对象的成员变量的值发生变化,则生成新的与之前不同的哈希码。
【实例】重写 hashCode() 方法。
当定义一个类时,如果没有使用关键字 extends 显式指定该类继承的父类,那么编译器自动添加 extends java.lang.Object。也就是说,任何一个类在定义时如果没有明确地继承一个父类,那么它将直接继承 Object 类。因此,可以说 Java 中的每个类都是 Object 类的直接或间接子类。
Object 类中定义了所有的 Java 类经常使用的方法,子类可以直接使用或覆盖后使用。由于 Object 类中定义的方法的逻辑并不一定适用于所有子类,因此大部分子类需要重写从 Object 类继承的方法才能使用。
public class E1{ ... }等价于:
public class E1 extend Object{ ... }E1 类默认继承了 Object 类。
Object 类的常用方法如下表所示。
Object类的常用方法 | 说明 |
---|---|
clone() | 保护方法,实现对象的浅复制,只有实现了 Cloneable 接口才可以调用该方法, 否则抛出 CloneNotSupportedException 异常 |
getClass() | final 方法,获得运行时类型 |
toString() | 返回该对象的字符串表现形式,常用于在调试过程中输出对象的属性值 |
equals() | 用于判断两个对象的逻辑是否相等,如判断两个对象的各属性值是否均相等 |
hashCode() | 为对象生成一个哈希值,用于哈希查找,在一些具有哈希功能的 Collection 中使用 |
finalize() | 用于释放资源,因为无法确定该方法什么时候被调用,所以很少使用 |
wait() | 使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait() 方法直等待,直到获得锁或被中断。wait(long timeout) 设定一个超时间隔,如果在规定时间内没有获得锁就返回 |
下面介绍几个常用的方法。
1) public String toString():返回该对象的字符串表现形式。Object类中定义的默认逻辑是返回对象的类型+@+hashCode值,其中的 hashCode 值默认将对象的内存地址转换为整型表示。
Object 类中 toString() 方法的默认实现如下:
public String toString{ return getClass().getName() + "@" + Integer.toHexString(hashCode()); }在实际开发中,经常需要按照对象的属性得到相应的字符串表现形式,因此,子类需要重写 toString() 方法。
另外,当使用 System.out.print() 方法打印一个对象时,如果该对象的值不为 null,那么底层调用该对象的 toString() 方法,先获取该对象的字符串表现形式,再打印该字符串。
【实例】重写toString()方法。
class Person { String name; int age; @Override public String toString() { return name + ",年龄:" + age; } } public class Demo { public static void main(String[] args) { Person p = new Person(); p.age = 20; p.name = "张三"; System.out.println("info:" + p.toString()); Demo t = new Deno(); System.out.println(t.toString()); // 这里应该调用toString方法来打印对象的字符串表示 } }运行结果为:
info:张三,年龄:20
chapter8n.Example8
2) public boolean equals(Object obj):比较某个对象是否与当前对象相等。调用成员方法 equals() 并指定参数为另一个对象,用来判断这两个对象是否是相同的。
这里的“相同”有默认和自定义两种方式。
- 默认地址比较:如果没有覆盖重写 equals() 方法,那么 Object 类中默认使用“==”运算符比较两个对象的地址,只要不是同一个对象,结果必然为 false。这种比较方式也被称为比较两个对象物理相等。
- 对象内容比较:如果希望进行对象的内容比较,即所有或指定的部分成员变量相同就判定两个对象相同,那么需要重写 equals() 方法,添加比较两个对象对应成员变量值的逻辑。这种比较方式也被称为比较两个对象逻辑相等。在实际开发中,对比较两个对象逻辑相等的应用非常广泛。
为了避免造成歧义,在开发过程中一般使用“==”运算符进行对象物理相等的判断,使用 equals() 方法进行对象逻辑相等的判断。
【实例】重写equals()方法。
import java.util.Objects; public class Person { private String name; private int age; @Override public boolean equals(Object o) { // 若对象的地址一样,则认为相同 if (this == o) return true; // 若参数为空,或者类型信息不一样,则认为不同 if (o == null || getClass() != o.getClass()) return false; // 转换为当前类型 Person person = (Person) o; // 要求基本数据类型的属性的值相等 return age == person.age && Objects.equals(name, person.name); } }这段代码充分考虑了对象为空和类型一致等问题,但方法内容并不是唯一的。大多数 IDE 都可以自动生成 equals() 方法的代码内容。
3) hashCode()方法:返回对象的是哈希码。在一些基于 Hash Table 算法的容器中,需要根据对象的哈希码计算对象在容器中的下标。如果将一个对象存入此类容器中,那么底层会调用该对象的hashCode()方法。
Hash 算法对 hashCode() 方法的实现有如下几点要求:
- 当在 Java 程序执行期间对同一对象多次调用 hashCode() 方法时,该方法必须始终返回相同的整数,前提是没有修改对象上 equals() 方法比较中使用的信息,该整数不需要从应用程序的一次执行到同一应用程序的另一次执行保持一致。
- 如果根据 equals(Object) 方法判断两个对象相等,那么调用这两个对象中的任意一个对象的 hashCode() 方法必须产生相同的整数结果。
- 如果根据 equals(Object) 方法判断两个对象不相等,那么不强制要求对两个对象中的每个调用 hashCode() 方法必须产生不同的整数结果。但是,开发者应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。
- Object 类中提供的 hashCode() 方法的默认实现逻辑是调用系统底层方法,将对象的内部地址转换成整数表示。由于不同对象的内部地址不同,因此返回的整数也一定不同,当使用 equals() 方法判断的是两个对象物理相等时,可以满足上述 3 点需求。但是,当开发者重写了 equals() 方法,改为判断两个对象逻辑相等时,hashCode() 方法的默认实现逻辑就无法满足上述 3 点需求。因此,当重写 equals() 方法时,也需要重写 hashCode() 方法。
与 equals() 方法类似,大多数 IDE 可以自动生成 equals() 方法的代码内容,其核心逻辑是基于对象所有参与逻辑相等比较的成员变量的值,经过特定的计算得到一个整数。在这种情况下,若两个对象参与计算的成员变量的值相等,则返回相同的哈希码;若其中一个对象的成员变量的值发生变化,则生成新的与之前不同的哈希码。
【实例】重写 hashCode() 方法。
class Person { String name; int age; public Person(String name, int age) { this.name = name; this.age = age; } @Override public int hashCode() { return Objects.hash(name, age); } } public class Demo { public static void main(String[] args) { Person p1 = new Person("小明", 15); Person p2 = new Person("小明", 15); Person p3 = new Person("小红", 13); System.out.println("p1.hashCode = " + p1.hashCode()); System.out.println("p2.hashCode = " + p2.hashCode()); System.out.println("p3.hashCode = " + p3.hashCode()); } }运行结果为:
p1.hashCode = 23458769
p2.hashCode = 23458769
p3.hashCode = 23653819