Java Object 类:11 个核心方法的原理、用法与实战
Object 是 Java 所有类的「根类」,所有类都直接 / 间接继承 Object,其 11 个核心方法定义了 Java 对象的通用行为(如相等性判断、哈希计算、垃圾回收等)。本文从「方法原理→重写规则→实战场景」全维度拆解,帮你彻底掌握 Object 类的核心用法。
一、Object 类核心定位
- 继承关系:所有类默认继承
java.lang.Object(无需显式写extends Object); - 核心价值:提供所有 Java 对象的通用方法,是 Java 面向对象的基础;
- 11 个核心方法:
toString()、equals()、hashCode()、getClass()、clone()、finalize()(已废弃)、wait()/wait(long)/wait(long, int)、notify()、notifyAll()。
二、11 个核心方法逐一拆解
1. toString ():对象的字符串表示
(1)默认实现
java
运行
// Object 源码
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
默认返回「类全限定名 + @ + 哈希值十六进制」,如 com.example.User@15db9742,可读性差。
(2)重写规则
必须返回有意义的字符串(包含对象核心属性),是调试 / 日志的核心方法。
(3)实战示例
java
运行
public class User {
private String name;
private Integer age;
// 重写toString()
@Override
public String toString() {
return "User{name='" + name + "', age=" + age + "}";
}
// 构造器+getter/setter省略
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public static void main(String[] args) {
User user = new User("张三", 20);
System.out.println(user); // 自动调用toString(),输出:User{name='张三', age=20}
}
}
2. equals ():对象相等性判断
(1)默认实现
java
运行
// Object 源码
public boolean equals(Object obj) {
return (this == obj);
}
默认用 == 比较对象引用(是否指向同一内存地址),而非对象内容。
(2)重写规则(必须遵守)
- 自反性:
x.equals(x)必须返回 true; - 对称性:
x.equals(y)→y.equals(x); - 传递性:
x.equals(y)且y.equals(z)→x.equals(z); - 一致性:多次调用结果一致(无修改的前提下);
- 非空性:
x.equals(null)必须返回 false。
(3)重写模板(结合 hashCode)
java
运行
@Override
public boolean equals(Object o) {
// 1. 引用相同,直接返回true
if (this == o) return true;
// 2. 为空或类型不同,返回false
if (o == null || getClass() != o.getClass()) return false;
// 3. 强转并比较核心属性
User user = (User) o;
return Objects.equals(name, user.name) && Objects.equals(age, user.age);
}
✅ 推荐用 Objects.equals() 避免空指针(Objects.equals(a,b) 会先判空)。
3. hashCode ():对象哈希值计算
(1)默认实现
返回对象的内存地址映射值(不同 JVM 实现不同),保证同一对象哈希值固定。
(2)核心规则(与 equals 强绑定)
- 若
x.equals(y) = true,则x.hashCode()必须等于y.hashCode(); - 若
x.hashCode() = y.hashCode(),x.equals(y)不一定为 true(哈希冲突); - 重写
equals()必须重写hashCode(),否则违反 HashMap/HashSet 等集合的规范。
(3)重写示例
java
运行
@Override
public int hashCode() {
// 用Objects.hash()自动处理空值,组合核心属性
return Objects.hash(name, age);
}
(4)反例(必避坑)
java
运行
// 错误:只重写equals,不重写hashCode
public class BadUser {
private String id;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BadUser badUser = (BadUser) o;
return Objects.equals(id, badUser.id);
}
// 未重写hashCode()
}
// 测试:HashMap 中无法正确识别相等对象
public static void main(String[] args) {
BadUser u1 = new BadUser();
u1.setId("001");
BadUser u2 = new BadUser();
u2.setId("001");
Map<BadUser, String> map = new HashMap<>();
map.put(u1, "张三");
System.out.println(map.get(u2)); // null(哈希值不同,定位不到)
}
4. getClass ():获取对象的 Class 实例
(1)源码与特性
java
运行
// Object 源码(native 方法,底层C实现)
public final native Class<?> getClass();
final方法,不可重写;- 返回对象的运行时类(
Class对象),是反射的核心入口; - 同一类的所有实例共享同一个
Class对象。
(2)实战示例(反射 / 类型判断)
java
运行
public static void main(String[] args) {
User user = new User("张三", 20);
// 1. 反射入口
Class<? extends User> clazz = user.getClass();
System.out.println(clazz.getName()); // com.example.User
// 2. 类型判断(比 instanceof 更严格,不考虑子类)
User user2 = new User("李四", 25);
System.out.println(user.getClass() == user2.getClass()); // true
// 3. 避免 instanceof 的子类误判
class SubUser extends User {
public SubUser(String name, Integer age) {
super(name, age);
}
}
SubUser subUser = new SubUser("王五", 30);
System.out.println(subUser instanceof User); // true
System.out.println(subUser.getClass() == User.class); // false
}
5. clone ():对象克隆
(1)源码与前提
java
运行
// Object 源码
protected native Object clone() throws CloneNotSupportedException;
protected方法,需重写为public;- 实现克隆的类必须实现
Cloneable接口(标记接口,无方法),否则抛CloneNotSupportedException。
(2)浅克隆 vs 深克隆
表格
| 类型 | 核心特点 | 适用场景 |
|---|---|---|
| 浅克隆 | 仅复制对象引用,对象内部的引用类型共享 | 无嵌套引用类型的简单对象 |
| 深克隆 | 复制对象及所有嵌套引用类型对象 | 有嵌套引用类型的复杂对象 |
(3)实战示例
java
运行
// 浅克隆示例
public class Address implements Cloneable {
private String city;
// 构造器+getter/setter+toString省略
public Address(String city) {
this.city = city;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class User implements Cloneable {
private String name;
private Address address; // 嵌套引用类型
// 浅克隆:仅复制address引用
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
// 深克隆:手动复制嵌套对象
public Object deepClone() throws CloneNotSupportedException {
User clone = (User) super.clone();
clone.address = (Address) address.clone(); // 克隆嵌套对象
return clone;
}
// 测试
public static void main(String[] args) throws CloneNotSupportedException {
User user = new User("张三", new Address("北京"));
// 浅克隆:address引用共享
User shallowClone = (User) user.clone();
shallowClone.getAddress().setCity("上海");
System.out.println(user.getAddress().getCity()); // 上海(原对象被修改)
// 深克隆:address独立
User deepClone = (User) user.deepClone();
deepClone.getAddress().setCity("广州");
System.out.println(user.getAddress().getCity()); // 上海(原对象不受影响)
}
}
6. finalize ():垃圾回收前的清理(已废弃)
(1)源码与特性
java
运行
// Object 源码(JDK9+ 标记为 @Deprecated)
protected void finalize() throws Throwable { }
- 垃圾回收器回收对象前调用,用于释放非 Java 资源(如文件句柄、网络连接);
- 执行时机不确定、可能不执行(JVM 退出前可能不触发 GC),已被
java.lang.ref.Cleaner替代。
(2)替代方案
java
运行
// 用 Cleaner 实现资源清理(推荐)
public class Resource implements AutoCloseable {
private static final Cleaner cleaner = Cleaner.create();
private final Cleaner.Cleanable cleanable;
public Resource() {
this.cleanable = cleaner.register(this, () -> {
// 清理逻辑(如关闭文件、释放连接)
System.out.println("资源被清理");
});
}
@Override
public void close() {
cleanable.clean(); // 手动触发清理
}
public static void main(String[] args) {
try (Resource resource = new Resource()) {
// 使用资源
} // 自动调用close()
}
}
7. wait ()/wait (long)/wait (long, int):线程等待
(1)核心作用
让当前线程释放对象锁,进入等待队列,直到被 notify()/notifyAll() 唤醒或超时。
(2)使用规则(必遵守)
- 必须在
synchronized代码块 / 方法中调用(持有对象锁),否则抛IllegalMonitorStateException; - 调用后线程释放锁,被唤醒后需重新竞争锁。
(3)实战示例(生产者 - 消费者)
java
运行
public class QueueDemo {
private final Queue<String> queue = new LinkedList<>();
private static final int MAX_SIZE = 5;
// 生产者
public synchronized void produce(String data) throws InterruptedException {
while (queue.size() == MAX_SIZE) {
wait(); // 队列满,等待
}
queue.add(data);
System.out.println("生产:" + data);
notifyAll(); // 唤醒消费者
}
// 消费者
public synchronized String consume() throws InterruptedException {
while (queue.isEmpty()) {
wait(); // 队列空,等待
}
String data = queue.poll();
System.out.println("消费:" + data);
notifyAll(); // 唤醒生产者
return data;
}
public static void main(String[] args) {
QueueDemo demo = new QueueDemo();
// 生产者线程
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
demo.produce("数据" + i);
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}).start();
// 消费者线程
new Thread(() -> {
for (int i = 0; i < 10; i++) {
try {
demo.consume();
Thread.sleep(200);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}).start();
}
}
8. notify ()/notifyAll ():唤醒等待线程
(1)核心区别
表格
| 方法 | 作用 | 注意事项 |
|---|---|---|
| notify() | 唤醒对象等待队列中的一个随机线程 | 可能导致线程饥饿(某线程一直不被唤醒) |
| notifyAll() | 唤醒对象等待队列中的所有线程 | 无饥饿问题,推荐优先使用 |
(2)使用规则
- 必须在
synchronized代码块 / 方法中调用; - 唤醒后线程不会立即执行,需等待当前线程释放锁后竞争锁。
三、核心方法重写优先级
表格
| 优先级 | 方法 | 重写必要性 | 核心场景 |
|---|---|---|---|
| 最高 | toString() | 必重写 | 调试、日志、打印对象 |
| 最高 | equals() | 必重写 | 对象相等性判断、集合存储 |
| 最高 | hashCode() | 必重写 | 与 equals 绑定,集合存储 |
| 中 | clone() | 按需重写 | 对象克隆(浅 / 深克隆) |
| 低 | finalize() | 不推荐重写 | 资源清理(用 Cleaner 替代) |
| 特殊 | wait/notify | 几乎不重写 | 线程同步(直接使用) |
| 特殊 | getClass() | 不能重写 | 反射、类型判断 |
四、常见面试题
-
Object 类有哪些核心方法?核心:toString ()、equals ()、hashCode ()、getClass ()、clone ()、finalize ()、wait ()/notify ()/notifyAll ();扩展:wait (long)、wait (long, int)。
-
equals () 和 == 的区别?
==:基本类型比较值,引用类型比较内存地址;equals():默认等价于==,重写后可比较对象内容。
-
重写 equals () 为什么必须重写 hashCode ()?保证相等的对象哈希值相同,否则 HashMap/HashSet 等集合无法正确识别相等对象(哈希冲突导致查找失败)。
-
wait () 和 sleep () 的区别?
- wait ():Object 方法,释放对象锁,需在 synchronized 中调用;
- sleep ():Thread 静态方法,不释放锁,可在任意位置调用。
-
clone () 的浅克隆和深克隆区别?浅克隆仅复制对象引用,嵌套对象共享;深克隆复制所有嵌套对象,完全独立。
五、实战避坑指南
-
equals () 重写避坑:
- 避免用
instanceof(子类会破坏对称性),优先用getClass() == o.getClass(); - 用
Objects.equals()避免空指针。
- 避免用
-
hashCode () 重写避坑:
- 尽量组合多个核心属性(减少哈希冲突);
- 保证 equals 相等的对象哈希值一定相等。
-
wait/notify 避坑:
- 用
while循环判断条件(而非if),避免虚假唤醒; - 优先用
notifyAll()而非notify(),避免线程饥饿。
- 用
-
clone () 避坑:
- 嵌套引用类型必须实现深克隆,否则数据共享导致 bug;
- 重写时修改访问修饰符为
public。
总结
- 核心基础:Object 是所有 Java 类的父类,11 个方法定义了对象的通用行为;
- 重写核心:toString ()、equals ()、hashCode () 是必重写方法,需严格遵守规则;
- 线程相关:wait ()/notify ()/notifyAll () 是线程同步的核心方法,必须在 synchronized 中调用;
- 避坑关键:equals/hashCode 强绑定、wait 用 while 判断条件、clone 区分浅 / 深克隆。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)