JavaSE常用API之Object类:Java万物之基
JavaSE常用API之Object类:Java万物之基
在Java的类层次结构中,Object
类位于顶端,是所有类的终极父类。Java中的每个类都直接或间接继承自Object
,因此掌握Object
类的核心方法是理解Java面向对象编程的基础。本文将深入解析Object
类的设计理念与常用方法,帮助开发者灵活运用这一“万类之母”。
一、Object类的核心地位
-
隐式继承
- 所有类默认继承自
Object
,无需显式声明。 - 示例:
public class MyClass { // 隐式继承自Object// ... }
- 所有类默认继承自
-
多态基础
- 任何对象都可赋值给
Object
类型的变量,支持向上转型。 - 示例:
Object obj = new MyClass(); // 合法,MyClass继承自Object
- 任何对象都可赋值给
-
核心方法
Object
类定义了11个基础方法,其中7个为非final方法(可被子类重写):public boolean equals(Object obj) public int hashCode() public String toString() protected Object clone() throws CloneNotSupportedException public final Class<?> getClass() protected void finalize() throws Throwable public final native void notify() public final native void notifyAll() public final native void wait(long timeout) throws InterruptedException public final void wait(long timeout, int nanos) throws InterruptedException public final void wait() throws InterruptedException
二、常用方法详解
1. equals(Object obj)
:对象相等性判断
(1)默认实现
- 功能:比较两个对象的引用是否相同(即是否指向同一内存地址)。
- 源码:
public boolean equals(Object obj) {return (this == obj); }
(2)重写规则
-
场景:当需要比较对象的内容是否相等时,需重写
equals()
方法。 -
重写原则(需满足等价关系):
- 自反性:
x.equals(x)
必须为true
。 - 对称性:若
x.equals(y)
为true
,则y.equals(x)
也为true
。 - 传递性:若
x.equals(y)
和y.equals(z)
为true
,则x.equals(z)
也为true
。 - 一致性:多次调用
x.equals(y)
结果相同(前提是对象状态未变)。 - 非空性:
x.equals(null)
必须为false
。
- 自反性:
-
示例:重写
equals()
方法public class Person {private String name;private int age;@Overridepublic boolean equals(Object obj) {if (this == obj) return true;if (obj == null || getClass() != obj.getClass()) return false;Person person = (Person) obj;return age == person.age && name.equals(person.name);} }
(3)与==
的区别
==
:比较引用(基本类型比较值)。equals()
:默认比较引用,重写后可比较内容。
2. hashCode()
:哈希码生成
(1)默认实现
- 功能:返回对象的内存地址的整数表示(由JVM实现)。
- 源码:
public native int hashCode(); // 本地方法
(2)重写规则
- 必须与
equals()
保持一致:若x.equals(y)
为true
,则x.hashCode()
必须等于y.hashCode()
。 - 最佳实践:
@Override public int hashCode() {return Objects.hash(name, age); // 使用Objects工具类 }
(3)应用场景
- 哈希表(如
HashMap
、HashSet
):根据哈希码快速定位元素。- 若重写
equals()
但不重写hashCode()
,会导致哈希表无法正常工作。
- 若重写
3. toString()
:对象字符串表示
(1)默认实现
- 格式:
类名@哈希码的十六进制
。 - 示例:
Person person = new Person(); System.out.println(person); // 输出:com.example.Person@7a81197d
(2)重写建议
- 目标:返回对象的可读信息,便于调试和日志记录。
- 示例:
@Override public String toString() {return "Person{name='" + name + "', age=" + age + "}"; }
4. clone()
:对象复制
(1)默认实现
- 功能:创建并返回对象的一个副本。
- 源码:
protected native Object clone() throws CloneNotSupportedException;
(2)使用限制
- 必须实现
Cloneable
接口:否则抛出CloneNotSupportedException
。 - 浅拷贝(Shallow Copy):
- 仅复制对象本身及基本类型字段,引用类型字段仍指向原对象。
- 示例:
public class Address {private String city;// getter/setter }public class Person implements Cloneable {private Address address;@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone(); // 浅拷贝} }
(3)深拷贝(Deep Copy)
- 需手动实现:递归复制所有引用类型字段。
- 示例:
@Override protected Object clone() throws CloneNotSupportedException {Person clone = (Person) super.clone();clone.address = (Address) this.address.clone(); // 深拷贝Addressreturn clone; }
5. getClass()
:获取运行时类
(1)功能
- 返回对象的运行时类(
Class
对象),常用于反射和类型检查。 - 示例:
Person person = new Person(); Class<?> clazz = person.getClass(); System.out.println(clazz.getName()); // 输出:com.example.Person
(2)与instanceof
的区别
getClass()
:精确判断对象类型(不考虑继承关系)。instanceof
:判断对象是否属于某个类或其子类。String str = "hello"; System.out.println(str instanceof Object); // true System.out.println(str.getClass() == Object.class); // false
三、线程相关方法
1. wait()
、notify()
、notifyAll()
(1)功能
wait()
:使当前线程等待,直到其他线程调用该对象的notify()
或notifyAll()
。notify()
:唤醒在此对象监视器上等待的单个线程。notifyAll()
:唤醒在此对象监视器上等待的所有线程。
(2)典型应用:生产者-消费者模型
public class ProducerConsumer {private final List<Integer> buffer = new ArrayList<>();private final int MAX_SIZE = 10;public void produce() throws InterruptedException {synchronized (this) {while (buffer.size() == MAX_SIZE) {wait(); // 缓冲区满,等待消费}buffer.add(1);notifyAll(); // 通知消费者}}public void consume() throws InterruptedException {synchronized (this) {while (buffer.isEmpty()) {wait(); // 缓冲区空,等待生产}buffer.remove(0);notifyAll(); // 通知生产者}}
}
四、finalize()方法
1. 功能
- 垃圾回收前的回调:当JVM确定对象不再被引用时,会调用
finalize()
方法(但不保证立即调用)。 - 源码:
protected void finalize() throws Throwable { }
2. 注意事项
- 不推荐使用:性能差,且无法保证资源及时释放。
- 替代方案:使用
try-with-resources
或AutoCloseable
接口。try (FileInputStream fis = new FileInputStream("file.txt")) {// 自动关闭资源 }
五、典型应用场景
1. 集合框架中的使用
equals()
和hashCode()
:Set<Person> personSet = new HashSet<>(); personSet.add(new Person("Alice", 25)); // 正确重写equals和hashCode才能保证元素唯一性
2. 自定义对象的序列化
toString()
:// 将对象转为JSON格式字符串 @Override public String toString() {return "{\"name\":\"" + name + "\",\"age\":" + age + "}"; }
3. 线程同步
wait()
和notify()
:public class Counter {private int count = 0;public synchronized void increment() throws InterruptedException {while (count > 0) {wait();}count++;notify();} }
六、注意事项
-
重写
equals()
必须重写hashCode()
- 否则违反
hashCode()
的约定,导致哈希集合(如HashMap
)无法正常工作。
- 否则违反
-
clone()
的深拷贝陷阱- 默认的
clone()
是浅拷贝,需手动实现深拷贝以避免引用共享问题。
- 默认的
-
finalize()
的弃用- Java 9开始标记为已过时,推荐使用显式资源管理(如
try-with-resources
)。
- Java 9开始标记为已过时,推荐使用显式资源管理(如
七、面试常见问题
-
为什么重写
equals()
时必须重写hashCode()
?- 确保相等的对象具有相同的哈希码,以维护哈希集合的一致性。
-
finalize()
方法的作用是什么?有什么问题?- 作用:垃圾回收前执行清理操作;问题:性能差、执行时机不确定。
-
Object
类中哪些方法不能被重写?getClass()
、notify()
、notifyAll()
、wait()
等被final
修饰的方法。
总结
Object
类作为Java类层次结构的根,定义了所有对象共有的行为和属性。合理重写equals()
、hashCode()
和toString()
方法是开发高质量Java代码的基础,而clone()
、wait()
等方法则为对象复制和线程同步提供了底层支持。在实际开发中,需注意方法重写的规范和陷阱,避免因误用导致的bug。随着Java版本的演进,Object
类的部分方法(如finalize()
)已逐渐被更安全、高效的机制替代,开发者应及时更新知识体系,选择最优实践。