【后端之旅】源码分析 Object 篇

38 阅读3分钟

Object 是所有对象的父类。学习 Java 的反射、格式输出、多线程 时,都离不开 Object 提供的基本方法。它内容不多,但它是整个面向对象(类)的基石。

实例方法

  • Object.instance.getClass() - 返回当前对象的运行时类

    Object obj = new ArrayList<>();
    
    System.out.println(obj.getClass() == ArrayList.class);  // true
    

    获得类对象后,就可以进一步获取类的名称、父类、接口等信息。

  • Object.instance.hashCode() - 返回当前对象的哈希值

    哈希值一般是当前对象的内存地址,是 32 位无符号整数,范围是 0 ~ 2^32 - 1

  • Object.instance.equals(Object obj) - 判断当前对象与给定对象是否相等,相等返回 true,否则返回 false

    使用的就是 == 判断符。其他类应当重写 equals(Object obj) 方法,以实现自定义的相等判断。

  • Object.instance.toString() - 返回当前对象的字符串表示

    默认返回 当前对象的运行时类名 + "@" + 内存地址

  • Object.instance.notify() - 唤醒正在等待当前对象的一个线程

    如果当前对象没有线程正在等待,则调用此方法没有任何效果。

    任意时刻都只有一个线程持有当前对象的锁,所以只有该持锁线程才能调用此方法。

    等待锁的线程中,只有一个线程能幸运地被唤醒(从锁等待池放入到锁竞争池)。而唤醒并不意味着立即往下执行,而是要持锁线程释放了当前对象的锁以后,被唤醒的线程才能继续执行。

  • Object.instance.notifyAll() - 唤醒正在等待当前对象的所有线程

    如果当前对象没有线程正在等待,则调用此方法没有任何效果。

    notify() 方法不同的是,本方法会把等待池中全部的线程都移至锁竞争池。

  • Object.instance.wait(long timeout) - 当前线程释放当前对象的锁,然后当前线程等待 timeout 毫秒,直到被当前对象的持锁线程唤醒或超时

    该方法的具体作用就是释放当前对象的锁,然后让当前线程进入锁等待池。

    如果当前对象没有线程正在等待锁,则调用此方法会立即返回。

    被当前对象的持锁线程唤醒的话,是进入到对象的锁竞争池,而不是立即往下执行。必须重新竞争到对象的锁以后,当前线程才能继续往下执行。

    如果超时,也是进入到对象的锁竞争池。

  • Object.instance.wait(long timeout, int nanos) - 当前线程释放当前对象的锁,然后当前线程等待 timeout 毫秒 + nanos 纳秒,直到被当前对象的持锁线程唤醒或超时

    在 Java 的实现都没有那么神奇。nanos 被要求必须大于等于 0,小于 1000000 (即 1 秒),然后大于 0 时对 timeout 加一,最后调用 wait(timeout)

    所以,请直接调用 wait(timeout) 实现相应功能即可。

  • Object.instance.wait() - 当前线程释放当前对象的锁,然后当前线程等待,直到被当前对象的持锁线程唤醒

    其实就是调用 wait(0),即无限期地等待。

小结

可以看到,Object 类既没有静态常量,也没有静态方法。这说明 Java 并不希望我们将 Object 作为工具类使用。并且实例方法也相当稀少,主要用于多线程时对对象锁的操作。