Java Object类所有方法详解
Java中,java\.lang\.Object 类是所有类的根类(超类),无论是自定义类、系统类,还是数组,都直接或间接继承自Object类。Object类中定义了11个核心方法(JDK 8及以上版本),这些方法为所有Java对象提供了基础行为,以下是每个方法的详细解析,包含方法定义、作用、使用场景及注意事项,可直接复制保存为 Java\_Object类方法详解\.md 文件使用。
一、Object类核心方法总览
Object类的11个方法分别是:
-
equals\(Object obj\) -
hashCode\(\) -
toString\(\) -
getClass\(\) -
clone\(\) -
finalize\(\) -
wait\(\) -
wait\(long timeout\) -
wait\(long timeout, int nanos\) -
notify\(\) -
notifyAll\(\)
其中,wait\(\)、notify\(\)、notifyAll\(\) 用于线程间通信;equals\(\) 和 hashCode\(\) 用于对象相等性判断;toString\(\) 用于对象的字符串表示;getClass\(\) 用于获取对象的运行时类信息;clone\(\) 用于对象复制;finalize\(\) 用于对象回收前的资源清理(已过时)。
二、各方法详细解析
1. equals(Object obj) —— 对象相等性判断
方法定义
public boolean equals(Object obj)核心作用
判断当前对象(this)与参数对象(obj)是否「相等」,默认实现是「引用相等」(即判断两个对象是否指向同一个内存地址),可被子类重写,实现「内容相等」的判断逻辑。
默认实现(Object类源码)
public boolean equals(Object obj) { return (this == obj);}重写规范(必须遵循)
-
自反性:对于任意非null对象x,x.equals(x) 必须返回true;
-
对称性:对于任意非null对象x和y,若x.equals(y)为true,则y.equals(x)也必须为true;
-
传递性:对于任意非null对象x、y、z,若x.equals(y)为true且y.equals(z)为true,则x.equals(z)必须为true;
-
一致性:多次调用x.equals(y),结果始终一致(只要x和y的内容未改变);
-
非null性:对于任意非null对象x,x.equals(null) 必须返回false。
常见使用场景
比较两个对象的内容是否相同,比如String类、Integer类等都重写了equals()方法:
-
String类:比较字符串的字符序列是否一致(而非引用);
-
Integer类:比较包装类对应的基本类型值是否相等。
注意事项
重写equals()方法时,必须同时重写hashCode()方法(后面会详细说明),否则会导致HashMap、HashSet等集合类无法正常工作。
2. hashCode() —— 获取对象的哈希值
方法定义
public native int hashCode()注:native关键字表示该方法是本地方法,由C/C++实现,直接操作底层内存。
核心作用
返回当前对象的哈希值(一个int类型的整数),哈希值是对象的内存地址经过哈希算法计算得到的结果,主要用于「快速查找」(如HashMap、HashSet等集合的底层实现)。
默认实现
默认返回对象的内存地址对应的哈希值,不同对象(不同内存地址)的哈希值一般不同(但存在哈希碰撞的可能,即不同对象哈希值相同)。
重写规范(与equals()配套)
-
若两个对象equals()返回true,则它们的hashCode()必须返回相同的值;
-
若两个对象equals()返回false,则它们的hashCode()可以返回相同的值(哈希碰撞),但尽量不同,以提高集合的查找效率;
-
同一对象多次调用hashCode(),返回的哈希值必须一致(只要对象内容未改变)。
常见使用场景
配合equals()方法,用于集合中对象的去重和查找:
-
HashMap:先通过hashCode()找到对象所在的哈希桶,再通过equals()判断是否是目标对象;
-
HashSet:判断两个对象是否重复,先比较hashCode(),若不同则直接认为不重复;若相同,再比较equals()。
注意事项
不要仅通过hashCode()判断两个对象是否相等,因为哈希碰撞可能导致不同对象的hashCode()相同,必须结合equals()方法。
3. toString() —— 获取对象的字符串表示
方法定义
public String toString()核心作用
返回当前对象的字符串描述,默认实现是「类名@哈希值(十六进制)」,可被子类重写,用于直观展示对象的核心信息。
默认实现(Object类源码)
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode());}示例(默认与重写)
-
默认效果:若自定义类未重写toString(),打印对象时会显示
com\.example\.User@1b6d3586; -
重写效果:User类重写toString()后,可打印
User\{id=1, name=\&\#39;张三\&\#39;, age=20\},直观看到对象属性。
常见使用场景
用于日志打印、调试程序,快速查看对象的属性信息,几乎所有自定义类都会重写该方法。
注意事项
重写toString()时,建议包含对象的核心属性,避免返回无意义的字符串;不要在toString()中调用可能抛出异常的方法。
4. getClass() —— 获取对象的运行时类
方法定义
public final Class<?> getClass()注:final关键字表示该方法不能被子类重写。
核心作用
返回当前对象的「运行时类对象」(Class对象),通过该对象可以获取类的所有信息(如类名、属性、方法、注解等),是Java反射机制的核心入口。
关键特性
-
运行时绑定:getClass()返回的是对象实际运行时的类,而非编译时的类(比如子类对象调用getClass(),返回的是子类的Class对象,而非父类);
-
同一个类的所有对象,调用getClass()返回的是同一个Class对象(因为Class对象是单例的)。
常见使用场景
-
反射操作:获取类的构造方法、成员方法、成员变量,动态调用方法、创建对象;
-
判断对象的实际类型:比如
obj\.getClass\(\) == User\.class(区别于obj instanceof User,instanceof会考虑继承关系,而getClass()只判断实际类型)。
注意事项
getClass()不能被重写,若想获取类信息,只能通过该方法或 类名\.class 的方式;不要通过getClass()判断对象是否是某个类的子类,应使用instanceof。
5. clone() —— 对象复制(克隆)
方法定义
protected native Object clone() throws CloneNotSupportedException注:protected修饰符表示该方法只能被本类、子类或同包类访问;native方法,底层由C/C++实现。
核心作用
创建并返回当前对象的一个副本(克隆体),默认实现是「浅克隆」(浅拷贝),即复制对象本身,但对象内部的引用类型属性,仍指向原对象的引用。
使用条件
要使用clone()方法,当前类必须满足两个条件:
-
实现
java\.lang\.Cloneable接口(该接口是标记接口,无任何抽象方法,仅用于标记该类可克隆); -
重写clone()方法,并将访问修饰符改为public(否则外部无法调用)。
浅克隆与深克隆的区别
-
浅克隆(默认):仅复制对象本身,对象内部的引用类型属性(如List、数组、自定义对象)不复制,克隆体和原对象共享这些引用属性;
-
深克隆:不仅复制对象本身,还会递归复制对象内部所有引用类型属性,克隆体和原对象完全独立,互不影响。
常见使用场景
需要创建一个与原对象内容相同,但又不影响原对象的副本时使用,比如:
-
对象的备份(修改副本不会影响原对象);
-
多线程场景中,避免多个线程操作同一个对象导致的线程安全问题。
注意事项
-
未实现Cloneable接口,调用clone()会抛出
CloneNotSupportedException; -
默认的clone()是浅克隆,若需要深克隆,需在重写的clone()方法中,手动复制引用类型属性;
-
构造方法不会被调用(克隆是直接复制内存,不经过构造方法初始化)。
6. finalize() —— 对象回收前的资源清理(已过时)
方法定义
protected void finalize() throws Throwable注:JDK 9及以上版本,该方法已被标记为过时(@Deprecated),推荐使用try-with-resources、Cleaner等方式替代。
核心作用
当Java垃圾回收器(GC)确定对象不再被引用时,会在回收对象内存之前,调用该方法,用于释放对象占用的资源(如文件流、网络连接、数据库连接等)。
关键特性
-
调用时机不确定:GC何时回收对象是不确定的,因此finalize()的调用时机也不确定,无法依赖它执行关键操作;
-
最多被调用一次:一个对象被GC回收时,finalize()只会被调用一次,若对象在finalize()中重新被引用,则后续不会再调用;
-
异常不影响GC:finalize()中抛出的异常会被忽略,不会影响GC的继续执行。
使用场景(已不推荐)
早期用于释放非Java层面的资源(如本地方法打开的资源),现在已被替代:
-
文件操作:使用try-with-resources自动关闭文件流;
-
网络/数据库连接:使用连接池管理,或try-with-resources自动关闭。
注意事项
不要依赖finalize()进行资源清理,因为其调用时机不确定,可能导致资源泄漏;JDK 9+建议使用Cleaner类实现资源自动清理。
7. wait() —— 线程等待(线程间通信)
方法定义
public final void wait() throws InterruptedException注:final修饰,不能被子类重写;调用该方法会抛出InterruptedException,需手动捕获或抛出。
核心作用
使当前线程(调用该方法的线程)释放当前对象的锁,并进入「等待状态」(WAITING),直到其他线程调用该对象的notify()或notifyAll()方法唤醒它,或线程被中断。
使用条件
调用wait()方法的线程,必须持有当前对象的锁(即必须在synchronized代码块或synchronized方法中调用),否则会抛出 IllegalMonitorStateException。
关键特性
-
释放锁:线程调用wait()后,会立即释放持有的对象锁,让其他线程有机会获取锁;
-
等待状态:线程进入等待状态后,不会占用CPU资源,直到被唤醒;
-
中断响应:若线程在等待过程中被中断(调用interrupt()方法),会抛出InterruptedException,并结束等待状态。
常见使用场景
线程间通信,实现线程的协同工作,比如:
-
生产者-消费者模型:消费者线程调用wait()等待,生产者线程生产数据后,调用notify()唤醒消费者;
-
线程同步:让某个线程等待特定条件满足后,再继续执行。
注意事项
-
必须在synchronized代码块/方法中调用,否则抛出异常;
-
wait()被唤醒后,线程不会立即执行,需重新获取对象锁后,才能继续执行;
-
避免「虚假唤醒」:建议将wait()放在while循环中,而非if判断中,防止线程被虚假唤醒后,跳过条件判断。
8. wait(long timeout) —— 带超时的线程等待
方法定义
public final void wait(long timeout) throws InterruptedException核心作用
与wait()方法功能类似,区别在于:若线程在「timeout毫秒」内未被其他线程唤醒,会自动唤醒并恢复执行;若timeout为0,则等同于wait()方法(无限等待)。
参数说明
timeout:等待的最长时间,单位是毫秒(ms),取值范围:0 ≤ timeout ≤ Long.MAX_VALUE。
使用场景
需要限制线程等待时间的场景,避免线程无限等待导致死锁,比如:
-
网络请求超时:线程等待网络响应,若超过指定时间未响应,则自动唤醒,执行超时处理逻辑;
-
资源获取超时:线程等待获取某个资源,若超过超时时间未获取到,则放弃等待。
注意事项
与wait()方法一致,需在synchronized代码块/方法中调用,支持中断响应;超时时间只是「最长等待时间」,若在超时前被唤醒,会提前恢复执行。
9. wait(long timeout, int nanos) —— 高精度超时等待
方法定义
public final void wait(long timeout, int nanos) throws InterruptedException核心作用
在wait(long timeout)的基础上,增加了纳秒级的精度,总等待时间 = timeout毫秒 + nanos纳秒(1毫秒 = 1000000纳秒)。
参数说明
-
timeout:毫秒数,≥0;
-
nanos:纳秒数,0 ≤ nanos < 1000000(超过则会进位到timeout毫秒)。
使用场景
需要高精度等待时间的场景(如实时系统、高精度计时任务),但实际开发中很少使用,因为Java的线程调度精度有限,纳秒级精度难以保证。
注意事项
与前两个wait()方法一致,需在synchronized代码块/方法中调用;nanos参数若超出范围,会自动调整(如nanos=1500000,会转为timeout+1毫秒,nanos=500000)。
10. notify() —— 唤醒单个等待线程
方法定义
public final void notify()注:final修饰,不能被子类重写。
核心作用
唤醒当前对象上「处于等待状态」的单个线程(随机唤醒一个,无法指定唤醒哪个线程),被唤醒的线程会从wait()方法返回,重新尝试获取对象锁,获取锁成功后继续执行。
使用条件
调用notify()方法的线程,必须持有当前对象的锁(即必须在synchronized代码块或synchronized方法中调用),否则会抛出 IllegalMonitorStateException。
关键特性
-
随机唤醒:唤醒当前对象上等待的线程中的一个,无法控制唤醒顺序;
-
不释放锁:调用notify()后,线程不会立即释放对象锁,需等到当前synchronized代码块/方法执行完毕,才会释放锁;
-
唤醒后需重新获取锁:被唤醒的线程不会立即执行,需等待唤醒它的线程释放锁后,重新竞争锁,竞争成功后才能继续执行。
常见使用场景
与wait()配合,实现线程间通信,比如生产者-消费者模型中,生产者生产数据后,调用notify()唤醒一个等待的消费者线程。
注意事项
若当前对象上没有等待的线程,调用notify()无任何效果;必须在synchronized代码块/方法中调用,否则抛出异常。
11. notifyAll() —— 唤醒所有等待线程
方法定义
public final void notifyAll()核心作用
唤醒当前对象上「所有处于等待状态」的线程,被唤醒的所有线程会重新尝试获取对象锁,竞争成功的线程继续执行,未竞争到锁的线程会进入阻塞状态(BLOCKED)。
使用条件
与notify()一致,必须在synchronized代码块或synchronized方法中调用,否则抛出 IllegalMonitorStateException。
与notify()的区别
-
notify():唤醒单个线程,随机选择;
-
notifyAll():唤醒所有等待线程,所有线程竞争锁,适用于需要所有等待线程都知晓条件变化的场景。
常见使用场景
当某个条件发生变化,需要所有等待该条件的线程都被唤醒时使用,比如:
-
资源更新:当共享资源被更新后,唤醒所有等待该资源的线程,让它们重新检查资源状态;
-
线程退出:主线程唤醒所有子线程,通知它们退出。
注意事项
唤醒所有线程会导致锁竞争加剧,可能影响性能,若只需唤醒一个线程,优先使用notify();若没有等待的线程,调用notifyAll()无任何效果。
三、核心方法关联总结
-
equals\(\)与hashCode\(\):必须配套重写,否则影响集合类(HashMap、HashSet)的正常使用; -
wait\(\)、notify\(\)、notifyAll\(\):三者配合使用,用于线程间通信,必须在synchronized代码块/方法中调用,核心是「释放锁-等待-唤醒-重新获取锁」; -
toString\(\)与getClass\(\):toString()用于展示对象信息,getClass()用于获取对象的运行时类,两者常配合用于调试; -
clone\(\):实现对象复制,需实现Cloneable接口并重写方法,默认浅克隆,深克隆需手动实现; -
finalize\(\):已过时,不推荐使用,资源清理优先使用try-with-resources。
四、总结
Object类的11个方法是Java所有对象的基础行为,掌握这些方法的作用、使用条件和注意事项,是学好Java的核心基础。其中,equals()、hashCode()、toString()是日常开发中最常用、必须重写的方法;wait()、notify()、notifyAll()是线程间通信的核心;getClass()是反射的入口;clone()用于对象复制;finalize()已过时,了解即可。
(注:文档部分内容可能由 AI 生成)
如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时





