一、Object类的核心地位

Object是Java中所有类的根父类,任何Java类都直接或间接继承自Object,其提供的基础方法为Java对象的通用操作、线程间协作提供了核心支持,其中wait()/notifyAll() 是实现线程阻塞与唤醒的核心方法,equals()/toString()/hashCode() 需按业务需求重写才能发挥实际作用。

二、Object类核心方法逐一解析

1. equals(Object obj)

  • 核心作用:用于比较两个对象是否相等,是对象内容比较的核心方法。
  • 原生特性:默认实现是通过==比较两个对象的内存地址,仅当两个对象指向同一内存地址时才返回true,无法满足业务层“属性相同即相等”的需求。
  • 使用要求:必须根据业务规则重写,重写时需保证比较逻辑的合理性,比如以对象的唯一标识(如学号、主键)作为比较依据。

2. toString()

  • 核心作用:将对象转换为字符串形式输出,主要用于日志打印、调试场景。
  • 原生特性:默认输出格式为类名@对象哈希值的十六进制编码,例如com.th0314.Student@1b6d3586,无法直观看到对象的属性信息。
  • 使用要求:重写后可自定义输出内容,一般将对象的所有核心属性拼接为字符串,提升调试效率。

3. hashCode()

  • 核心作用:返回对象的哈希值,该值可作为对象在内存中的临时唯一标识,常用于HashMap、HashSet等哈希集合的元素存储与查找。
  • 原生特性:默认基于对象的内存地址生成哈希值,两个内容相同但地址不同的对象,原生hashCode()返回值不同。
  • 强制规范:与equals()强绑定重写,若重写了equals()则必须重写hashCode(),保证equals()返回true的两个对象,hashCode()返回值一定相等;反之hashCode()相等的对象,equals()不一定相等。

4. wait()

// 线程阻塞核心方法,重点掌握

  • 核心作用:使当前调用该方法的线程进入阻塞等待状态(WAITING),直到其他线程通过notify/notifyAll()唤醒。
  • 关键特性1:调用后会立即释放当前线程持有的该对象的锁,避免线程死锁。
  • 关键特性2:必须在synchronized同步方法/同步代码块中调用,否则会抛出IllegalMonitorStateException异常。
  • 触发场景:常用于生产者-消费者模型中,当资源不满足操作条件时(如队列满、队列空),让线程阻塞等待。

5. notifyAll()

// 线程唤醒核心方法,与wait()配套使用

  • 核心作用:唤醒所有因调用该对象的wait()方法而阻塞的线程,被唤醒的线程会进入锁竞争阶段,竞争成功后继续执行。
  • 对比说明:Object类还提供notify()方法,仅能唤醒单个阻塞线程,易出现“线程饿死”问题,实际开发中优先使用notifyAll() 保证线程协作的可靠性。
  • 关键特性:调用后不会立即释放对象锁,需等待当前同步方法/代码块执行完毕,锁才会被释放。

三、核心方法重写示例(Student类)

package com.th0314;

class Student {
    // 定义对象核心属性
    String name;
    int age;
    int score;
    String stuID; // 唯一标识,作为equals/hashCode重写依据

    // 构造方法:初始化属性
    public Student(String name, int age, int score, String stuID) {
        this.name = name;
        this.age = age;
        this.score = score;
        this.stuID = stuID;
    }

    // 重写toString():直观打印对象属性,替代原生的类名@哈希值
    @Override
    public String toString() {
        return "姓名:" + name + ",年龄:" + age + ",分数:" + score + ",学号:" + stuID;
    }

    // 重写equals():以学号stuID为唯一判断依据,属性相同即相等
    @Override
    public boolean equals(Object o) {
        // 地址相同,直接返回true
        if (this == o) return true;
        // 对方为null或类型不一致,返回false
        if (o == null || getClass() != o.getClass()) return false;
        // 类型强转后比较核心属性
        Student student = (Student) o;
        return stuID.equals(student.stuID);
    }

    // 重写hashCode():与equals绑定,基于stuID生成哈希值
    @Override
    public int hashCode() {
        return java.util.Objects.hash(stuID);
    }
}

// 测试类
public class TestObject {
    public static void main(String[] args) {
        // 创建两个属性相同、地址不同的Student对象
        Student stu1 = new Student("张三", 18, 90, "2019001");
        Student stu2 = new Student("张三", 18, 90, "2019001");

        // 测试重写后的equals()
        System.out.println(stu1.equals(stu2)); // 输出true,按属性比较
        // 测试重写后的toString()
        System.out.println(stu1); // 输出:姓名:张三,年龄:18,分数:90,学号:2019001
        // 测试重写后的hashCode()
        System.out.println(stu1.hashCode()); // 两个对象返回相同哈希值
        System.out.println(stu2.hashCode());
    }
}

四、重写关键注意事项

  1. equals()重写需保证自反性、对称性、传递性、一致性,避免随意编写比较逻辑。
  2. 哈希集合(HashMap/HashSet)中,对象的hashCode()值在对象生命周期内尽量保持不变,否则会导致元素查找失败。
  3. wait()/notifyAll()仅能操作当前对象的锁,即调用者必须是同步锁的持有对象,否则触发异常。
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐