记录下自己阅读过程的笔记,如有错误,欢迎指正!
源码参考:https://github.com/kangjianwei/LearningJDK/tree/master
1. 基本介绍
- 在 Java 中,
Object
类是类层次结构的根类
- 几乎每个 Java 类都直接或间接继承自
Object
类,意味着每个类都继承了 Object
的方法
- 类结构:

2. 源码分析
2.1 静态代码块及本地方法注册
| |
| private static native void registerNatives(); |
| static { |
| registerNatives(); |
| } |
-
本地方法声明:registerNatives()
- 关键字
native
表示这个方法是通过本地代码(如 C/C++)实现的接口,这些代码直接与底层系统的资源或系统 API 交互
registerNatives()
方法的主要作用是在内存中注册由本地方法实现的一些关键函数,这些函数通常是性能敏感的,直接与操作系统层交互。这样做可以提高方法调用的效率,避免每次调用时都进行查找和链接过程
-
静态初始化块:
- 在类被 Java 虚拟机加载时执行,且只执行一次,静态代码块常用于执行类级别的初始化代码
- 代码块中调用了
registerNatives()
方法来初始化与对象操作相关的本地方法,确保这些方法在被 Java 代码调用前已正确链接
2.2 getClass()
| |
| public final native Class<?> getClass(); |
- 这里的
Class<?>
表示方法返回一个 Class
类型的对象,其中 ?
是一个通配符,表示任何类型。在实际使用中,这个返回类型会更具体地表达为 Class<? extends |X|>
,这里的 |X|
表示调用 getClass()
的对象的类型
- 功能描述:
getClass()
方法返回一个 Class
类型的对象,该对象在 Java 中代表了调用此方法的对象的实际运行时类,通过这个返回的 Class
对象,可以访问关于类的各种信息,如类的名字、包含的方法、实现的接口
2.3 hashCode()
| |
| public native int hashCode(); |
- 功能描述:
hashCode()
方法的主要功能是为对象提供一个哈希码值,这个值主要被用于支持哈希表的使用,例如在 Java 集合框架中广泛使用的 HashMap
- 哈希码是根据对象的内部状态计算出的一个整数,用于确定对象在哈希表中的位置,以实现快速的查找、插入和删除操作
- 约定和规则:
- 重复调用一致性:对同一个对象多次调用
hashCode()
方法,必须始终返回相同的整数,前提是对象用于 equals
比较的信息没有被修改
- 等价对象的哈希码相等:为了确保对象能在哈希表中正确存储和检索,规定如果两个对象通过
equals(Object)
方法判断相等,那么这两个对象调用 hashCode()
必须返回相同的整数值
- 不等对象的哈希码优化:为了提高哈希表的性能,最好为不同的对象生成不同的哈希码,减少哈希碰撞,从而优化数据结构的性能
2.4 equals(Object obj)
| |
| |
| public boolean equals(Object obj) { |
| return (this == obj); |
| } |
- 功能描述:
equals()
方法用于确定调用对象与作为参数传递的对象(obj
)是否 “相等”
Object
类的实现中,仅当两个对象引用指向同一内存地址时,才认为它们相等
- 等价关系规则:
- 自反性:对于任何非空引用值
x
,x.equals(x)
必须返回 true
- 对称性:对于任何非空引用值
x
和 y
,x.equals(y)
应当仅在 y.equals(x)
也返回 true
时返回 true
- 传递性:如果
x.equals(y)
和 y.equals(z)
都返回 true
,则 x.equals(z)
也应返回 true
- 一致性:只要对象
x
和 y
的等价比较中用到的信息没有改变,反复调用 x.equals(y)
应当始终返回同样的结果
- 对 null 的比较:对于任何非空引用值
x
,x.equals(null)
应当返回 false
- 实现注意事项:
- 在自定义类中重写
equals()
方法时,应确保遵守上述等价关系的规则
- 当重写
equals()
方法时,也应该重写 hashCode()
方法,以保持 hashCode()
的一般约定,即相等的对象必须具有相等的哈希码
- 方法作用:
- Java 中,不同于基本数据类型的比较(使用
==
),对象比较更复杂,因为对象的 “等价性” 可以根据实际需求定义(如属性值相等),equals()
方法提供了一种标准方式来定义两个对象是否等价
- 在 Java 的集合框架中,例如
HashMap
和 HashSet
,对象是否相等直接影响到对象的存储和检索,正确实现 equals()
方法是使用这些集合的前提
2.5 clone()
| |
| |
| protected native Object clone() throws CloneNotSupportedException; |
2.6 toString()
| |
| |
| public String toString() { |
| return getClass().getName() + "@" + Integer.toHexString(hashCode()); |
| } |
toString()
方法提供了一种将对象转换为人类可读的字符串形式的方式,对于调试和日志记录非常有用,建议所有子类重写此方法
2.7 notify()
| |
| |
| public final native void notify(); |
-
notify()
方法的核心功能是在多线程环境中管理线程的等待与唤醒机制。它被用来唤醒一个在此对象上调用 wait()
方法而进入等待状态的线程
-
随机唤醒:当多个线程在某个对象的锁上调用 wait()
方法后进入等待状态时,notify()
方法可以从这些等待的线程中随机选择一个线程,使其从等待状态中返回,准备继续执行
-
线程状态变化:
- 被唤醒的线程仍需竞争对象锁。只有当前持有锁的线程释放锁后,被唤醒的线程才有机会获取锁并继续执行
- 唤醒并不意味着立即执行。被唤醒的线程将重新参与竞争该对象锁,其竞争的条件与其他可能正在等待锁的线程无异
-
调用条件:notify()
方法必须由锁的当前持有者调用,即在对象的同步方法或同步块中使用。如果一个线程试图在未持有对象锁的情况下调用 notify()
,会抛出 IllegalMonitorStateException
-
线程如何成为锁的当前持有者:
| public synchronized void synchronizedMethod() { |
| |
| } |
- 同步语句块:可以指定锁定任何对象,包括
this
(当前实例)、类对象或任何其他对象
| public void someMethod() { |
| synchronized (this) { |
| |
| } |
| } |
- 类的同步静态方法:锁定的是类的
Class
对象,而非类的某个实例
| public static synchronized void synchronizedStaticMethod() { |
| |
| } |
2.8 notifyAll()
| |
| |
| public final native void notifyAll(); |
- 全面唤醒:相比
notify()
随机唤醒单个线程,notifyAll()
确保所有等待的线程都能得到处理机会
- 竞争公平:所有被唤醒的线程将与其他可能正在尝试同步此对象的线程一起,公平地竞争获取对象锁
- 使用条件与规范:
notifyAll()
方法必须由锁的当前持有者调用。如果在未持有对象锁的情况下调用,将抛出 IllegalMonitorStateException
,因为只有锁的持有者才能安全地修改等待条件,并通知所有等待线程
2.9 wait
2.9.1 wait(long timeout)
| |
| public final native void wait(long timeout) throws InterruptedException; |
wait(long timeout)
方法使当前线程暂停并释放它持有的对象锁,进入等待状态,直到发生以下事件之一:
- 被通知: 如果有其他线程对此对象调用了
notify()
或 notifyAll()
,当前线程可能被唤醒
- 超时: 如果指定的等待时间结束,当前线程会自动唤醒
- 被中断: 如果当前线程在等待期间被中断,它会抛出
InterruptedException
- 虚假唤醒:指线程可能在没有任何明确通知的情况下唤醒。为了处理这种情况,等待通常应该放在一个循环中,以确保等待的条件确实得到了满足
- 代码示例:
| Thread consumerThread = new Thread(() -> { |
| synchronized (sharedResource) { |
| while (!dataReady) { |
| try { |
| System.out.println("消费者正在等待数据准备好..."); |
| |
| sharedResource.wait(5000); |
| if (dataReady) { |
| System.out.println("消费者拿到数据!"); |
| } else { |
| System.out.println("消费者超时! 无可用数据"); |
| } |
| } catch (InterruptedException e) { |
| System.out.println("消费者被中断"); |
| } |
| } |
| } |
| }); |
2.9.2 wait(long timeout, int nanos)
| |
| public final void wait(long timeout, int nanos) throws InterruptedException { |
| if (timeout < 0) { |
| |
| throw new IllegalArgumentException("timeout value is negative"); |
| } |
| |
| |
| if (nanos < 0 || nanos > 999999) { |
| throw new IllegalArgumentException( |
| "nanosecond timeout value out of range"); |
| } |
| |
| |
| if (nanos > 0) { |
| timeout++; |
| } |
| |
| |
| wait(timeout); |
| } |
- 功能描述:
wait(long timeout, int nanos)
方法使得当前线程可以在释放对象锁的同时等待至多 timeout
毫秒加 nanos
纳秒。如果在此期间:
- 被通知: 如果有其他线程对此对象调用了
notify()
或 notifyAll()
,当前线程可能被唤醒
- 超时: 如果指定的等待时间结束,当前线程会自动唤醒
- 被中断: 如果当前线程在等待期间被中断,它会抛出
InterruptedException
- 方法作用:提供了比毫秒更细的时间控制单位,即纳秒,对于需要极高时间精度的应用场景非常重要
2.9.3 wait()
| |
| public final void wait() throws InterruptedException { |
| wait(0); |
| } |
wait()
方法调用 wait(long timeout)
方法并传递 0
作为参数,表示允许当前线程放弃对象锁并无限期地等待,直到其他线程对此对象调用 notify()
或 notifyAll()
方法唤醒它,或者当前线程被中断
2.10 finalize()
| |
| protected void finalize() throws Throwable { } |
- 在 Java 早期,
finalize()
是处理对象销毁前资源释放的主要方式,它允许在对象被垃圾收集器回收之前执行清理操作
- 理论上,
finalize()
方法中可以采取措施使对象再次可用(例如,重新赋予引用),但通常不推荐,因为会导致对象回收行为变得不可预测
- 从 Java 9 开始,
finalize()
方法已被标记为过时,因为它可能导致不稳定和效率低下的代码
3. 总结
3.1 方法概览
getClass()
:返回对象的运行时类。提供了动态获取类信息的能力,是 Java 反射机制的基础之一
hashCode()
:返回对象的哈希码,主要用于哈希表(如 HashMap
)中。它需要与 equals()
方法保持一致,即相等的对象必须有相同的哈希码
equals(Object obj)
:检测某个对象是否等于当前对象。通常需要在自定义类中重写以实现逻辑上的 “相等”
clone()
:创建并返回此对象的一个副本。默认行为是浅拷贝,但可以被重写实现深拷贝
toString()
:返回对象的字符串表示,通常包含类名和哈希码的无符号十六进制表示。通常被重写以提供更多的实例信息
notify()
和 notifyAll()
:用于唤醒在此对象监视器上等待的单个线程或所有线程。这些方法必须在同步块内调用,且调用者必须是对象锁的当前持有者
wait()
方法族(wait()
, wait(long timeout)
, wait(long timeout, int nanos)
:使当前线程放弃对象锁并进入等待状态,直到被通知(notify
/notifyAll
)或中断。用于线程间的协调和通信
finalize()
:在垃圾收集器回收对象之前调用,用于清理资源。已被废弃并不推荐使用,因为它不可预测、效率低下且容易出错。建议使用 try-with-resources
或 Cleaner
类
3.2 归纳
- 线程同步与通信:
wait()
, notify()
, 和 notifyAll()
是 Java 中实现线程间同步和通信的基本机制。这些方法在使用时需要特别注意同步块的设计,以避免死锁或过早通知等问题
- 对象克隆:
clone()
方法提供了对象复制的能力,但需要注意浅拷贝与深拷贝的区别及其对应用的影响
- 哈希与等价:
hashCode()
和 equals()
方法定义了对象哈希存储和等价比较的标准,重写这些方法时必须遵循一定的约定,以保证它们的一致性
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix