Object 类是 Java 所有类的父类,无论是直接继承还是间接继承,所有的 Java 类都拥有 Object 类中定义的方法,理解这些方法是掌握 Java 面向对象编程的基础。
Object 类位于 java.lang 包中,它是一个 final 类,不能被继承。
下面我将这些方法分为几类进行详细说明,并附上代码示例。
Object 类的核心方法总览
| 方法签名 | 方法分类 | 描述 |
|---|---|---|
public final native Class<?> getClass() |
对象信息 | 返回此 Object 的运行时类。 |
public int hashCode() |
对象信息 | 返回该对象的哈希码值。 |
public boolean equals(Object obj) |
对象比较 | 指示其他某个对象是否与此对象“相等”。 |
protected native Object clone() throws CloneNotSupportedException |
对象创建 | 创建并返回此对象的一个副本。 |
public String toString() |
对象信息 | 返回该对象的字符串表示。 |
public final native void notify() |
线程通信 | 唤醒在此对象监视器上等待的单个线程。 |
public final native void notifyAll() |
线程通信 | 唤醒在此对象监视器上等待的所有线程。 |
public final native void wait() throws InterruptedException |
线程通信 | 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。 |
public final native void wait(long timeout) throws InterruptedException |
线程通信 | 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。 |
protected void finalize() throws Throwable |
垃圾回收 | 当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。(已废弃) |
详细解析与示例
getClass()
- 作用: 返回一个
Class对象,该对象表示对象的运行时类,这个Class对象包含了类的完整信息,如类名、父类、接口、方法、字段等。 - 特点:
final方法,不能被重写。native方法,由 JVM 实现,效率高。
- 示例:
String str = "Hello, World!"; Class<?> clazz = str.getClass(); System.out.println(clazz.getName()); // 输出: java.lang.String System.out.println(clazz.getSimpleName()); // 输出: String
hashCode()
-
作用: 返回一个整数值,作为该对象的“哈希码”,哈希码的主要作用是在哈希表(如
HashMap,HashSet)中确定对象的存储位置。 -
特点:
- 约定:
- 在 Java 应用程序执行期间,如果用于
equals比较的信息没有被修改,那么同一个对象多次调用hashCode()方法必须返回相同的整数。 - 如果两个对象根据
equals(Object)方法是相等的,那么这两个对象的hashCode()方法必须返回相同的整数。 - 如果两个对象根据
equals(Object)方法是不相等的,那么这两个对象的hashCode()方法不必须返回不同的整数(但这样做可以提高哈希表的性能)。
- 在 Java 应用程序执行期间,如果用于
- 默认实现:
Object类的hashCode()方法返回一个基于对象内存地址的哈希码,因此即使两个内容完全相同但内存地址不同的对象,其默认的hashCode()也不同。
- 约定:
-
示例:
Person p1 = new Person("Alice", 30); Person p2 = new Person("Alice", 30); System.out.println(p1.hashCode()); // 输出一个基于内存地址的哈希码 System.out.println(p2.hashCode()); // 输出另一个基于内存地址的哈希码 // 在下面自定义 equals 和 hashCode 后,p1 和 p2 的哈希码将相同
equals(Object obj)
-
作用: 比较两个对象是否“相等”。
-
特点:
- 默认实现:
Object类的equals方法内部使用 比较两个对象的内存地址,只有当两个引用指向同一个对象时,才返回true。 - 重写约定: 我们会重写
equals方法来比较对象的“内容”是否相等,重写equals时,必须同时重写hashCode方法,以遵守上述的约定。
- 默认实现:
-
示例:
// 默认的 equals 比较 String s1 = new String("hello"); String s2 = new String("hello"); System.out.println(s1.equals(s2)); // 输出 true,因为 String 类重写了 equals Person p1 = new Person("Alice", 30); Person p2 = new Person("Alice", 30); System.out.println(p1.equals(p2)); // 输出 false,因为 Person 类未重写 equals // 自定义 Person 类并重写 equals 和 hashCode class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = 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); } @Override public int hashCode() { return Objects.hash(name, age); } } Person p3 = new Person("Alice", 30); Person p4 = new Person("Alice", 30); System.out.println(p3.equals(p4)); // 输出 true
toString()
-
作用: 返回一个字符串表示,用于描述对象,这个字符串通常包含类的名字和有用的信息,方便调试和日志打印。
-
特点:
- 默认实现: 返回一个格式为
getClass().getName() + '@' + Integer.toHexString(hashCode())的字符串。com.example.Person@15db9742。 - 重写约定: 几乎所有情况下,我们都会重写
toString()方法,使其返回一个更有意义的、可读的字符串。
- 默认实现: 返回一个格式为
-
示例:
class Person { private String name; private int age; // ... 构造函数 ... @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } } Person p = new Person("Bob", 25); System.out.println(p); // 隐式调用 p.toString() // 输出: Person{name='Bob', age=25}
clone()
-
作用: 创建并返回一个对象的新副本,即“浅拷贝”。
-
特点:
native方法,性能高。- 受保护:
clone()方法是protected的,因此外部不能直接调用一个对象的clone()方法,只有实现了Cloneable接口的类才能调用Object的clone()方法。 - 浅拷贝: 默认的
clone()方法会复制对象的所有字段,对于基本数据类型,会复制其值;对于引用数据类型,只会复制引用地址,而不是引用指向的对象,原始对象和克隆对象的引用类型字段会指向同一个对象。 - 需要实现接口: 要使用
clone(),类必须实现java.lang.Cloneable接口(这是一个标记接口,没有方法),否则会抛出CloneNotSupportedException。
-
示例:
class Address { String city; public Address(String city) { this.city = city; } } class Employee implements Cloneable { String name; Address address; public Employee(String name, Address address) { this.name = name; this.address = address; } // 重写 clone 方法 @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); // 调用 Object 的 clone() 方法,执行浅拷贝 } @Override public String toString() { return "Employee{name='" + name + "', address=" + address.city + "}"; } } public class Main { public static void main(String[] args) throws CloneNotSupportedException { Address addr = new Address("New York"); Employee original = new Employee("John", addr); Employee cloned = (Employee) original.clone(); System.out.println("Original: " + original); System.out.println("Cloned: " + cloned); // 修改克隆对象的 address cloned.address.city = "Boston"; System.out.println("\nAfter modifying cloned's address:"); System.out.println("Original: " + original); // 输出 Original: Employee{name='John', address=Boston} System.out.println("Cloned: " + cloned); // 输出 Cloned: Employee{name='John', address=Boston} // 原始对象的地址也被修改了,证明了浅拷贝的特性 } }注意:
clone()方法由于存在一些问题(如接口设计不佳、浅拷贝的陷阱),通常不推荐使用,更推荐使用拷贝构造函数或序列化/反序列化的方式来创建对象的深拷贝。
notify(), notifyAll(), wait()
- 作用: 这三个方法是 Java 多线程编程中的核心,用于线程间的通信和同步。
- 特点:
- 它们必须在同步代码块或同步方法中调用,否则会抛出
IllegalMonitorStateException。 - 调用这些方法的当前线程必须拥有该对象的监视器锁。
wait(): 使当前线程等待,直到其他线程调用此对象的notify()或notifyAll()方法。wait()会释放锁。notify(): 随机唤醒一个在此对象监视器上等待的线程。notifyAll(): 唤醒所有在此对象监视器上等待的线程,它们会竞争获取锁。
- 它们必须在同步代码块或同步方法中调用,否则会抛出
- 示例: 这三个方法通常配合
synchronized关键字一起使用,是生产者-消费者模型等经典场景的基础。
finalize()
- 作用: 垃圾回收器在回收一个对象之前,会调用该对象的
finalize()方法。 - 特点:
- 已废弃: 从 Java 9 开始,
finalize()方法被标记为deprecated(废弃),不推荐在新代码中使用。 - 不可靠: JVM 不保证
finalize()一定会被调用,例如程序正常退出时。 - 性能问题:
finalize()的执行时机不确定,且会严重影响垃圾回收的性能。 - 替代方案: 如果需要执行清理操作(如关闭文件、网络连接),应该使用
try-finally块或try-with-resources语句。
- 已废弃: 从 Java 9 开始,
| 方法 | 是否必须重写 | 关键点 |
|---|---|---|
getClass() |
否 | final, native, 用于获取运行时类型信息。 |
hashCode() |
当重写 equals() 时必须重写 |
保证 equals 相等的对象 hashCode 必须相等。 |
equals(Object) |
当需要自定义“相等”逻辑时重写 | 默认比较内存地址,重写后应比较内容。 |
toString() |
强烈建议重写 | 默认输出无意义信息,重写后用于调试和日志。 |
clone() |
通常不推荐使用 | 实现复杂,易出错(浅拷贝陷阱),推荐其他拷贝方式。 |
notify(), notifyAll(), wait() |
否 | 多线程同步通信的基础,必须在同步代码块中调用。 |
finalize() |
已废弃,不应使用 | 不可靠,影响性能,使用 try-finally 或 try-with-resources 替代。 |
掌握 Object 类的方法是理解 Java 面向对象机制和高级特性的基石。equals 和 hashCode 的正确使用,以及 toString 的重写,是日常开发中最频繁、最重要的实践。
