在Java编程语言中,Object类是所有类的终极超类。这意味着任何Java对象都继承自Object,并可以使用其定义的方法。熟练掌握Object类的核心方法,不仅是编写健壮代码的基础,也是应对大厂Java面试的常见考点。本文将深入解析其12个核心方法,涵盖原理、使用示例与常见误区。
首先,我们来看一下Object类的完整方法列表:
public class Object{
public Object(){}
public final native Class<?> getClass();
public native int hashCode();
public boolean equals(Object obj);
protected native Object clone() throws CloneNotSupportedException;
public String toString();
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;
protected void finalize() throws Throwable{}
}
equals(Object obj)
这个方法用于比较两个对象是否“相等”。在Object类的默认实现中,它进行的是引用比较(即==比较),只有当两个引用指向堆内存中的同一个对象时,才返回true。
Object obj1 = new Object();
Object obj2 = new Object();
Object obj3 = obj1;
System.out.println(obj1.equals(obj2)); // false
System.out.println(obj1.equals(obj3)); // true
然而,许多JDK内置类(如String、Integer)以及我们自定义的类都会重写此方法,以实现基于对象内容(属性值)的比较,这更符合业务逻辑上的“相等”概念。重写equals方法通常遵循以下模式:
@Override
public boolean equals(Object obj){
if(this == obj){
return true;
}
if(obj == null || getClass() != obj.getClass()){
return false;
}
MyClass other = (MyClass) obj;
return Objects.equals(this.someField, other.someField);
}
hashCode()
hashCode()返回对象的哈希码,是一个由本地方法生成的int类型整数。默认实现通常与对象的内存地址相关。
哈希码在基于哈希的集合类中至关重要,例如HashMap、HashSet会利用它来快速定位元素的存储桶(bucket),从而提高查找效率。
一个重要的契约是:如果两个对象根据equals(Object)方法比较是相等的,那么调用这两个对象的hashCode()方法必须产生相同的整数结果。 因此,当你重写了equals方法时,必须同时重写hashCode方法,以确保相等的对象具有相等的哈希码。可以使用java.util.Objects.hash()工具方法来方便地生成。
@Override
public int hashCode(){
return Objects.hash(someField);
}
clone()
clone()方法用于创建并返回当前对象的一个副本。要使用此方法,类必须实现Cloneable接口,否则会抛出CloneNotSupportedException。
Object类提供的默认clone()实现是“浅拷贝”(shallow copy),即复制对象本身,但对于对象内部的引用类型字段,复制的只是引用地址,新旧对象将共享这些引用指向的同一个子对象。
class MyClass implements Cloneable{
@Override
protected Object clone() throws CloneNotSupportedException{
return super.clone();
}
}
finalize()
这是一个在垃圾回收器(Garbage Collector)确定该对象不再被引用,并准备回收其内存之前,由JVM调用的方法。开发者可以重写此方法来执行一些资源清理工作,例如关闭文件流、网络连接等。
图:JVM垃圾回收与finalize方法调用示意图
然而,需要注意,finalize()的执行时机是不确定的,甚至不保证一定会被执行(例如JVM提前退出)。因此,在Java的现代编程实践中,强烈不建议依赖finalize()进行资源清理,而应使用try-with-resources语句或显式调用close()方法。
@Override
protected void finalize() throws Throwable{
try{
// 清理资源的代码(不推荐)
} finally{
super.finalize();
}
}
getClass()
这是一个final方法,返回此对象的运行时类(Class对象)。它提供了在程序运行时获取对象类型信息的能力,是Java反射机制的基石。
Object obj = new Object();
System.out.println(obj.getClass()); // 输出:class java.lang.Object
notify(), notifyAll(), wait()
这三个方法是Java实现线程间通信(等待/通知机制)的核心,用于协调多个线程对共享资源的访问。它们必须在synchronized同步块或同步方法内部调用,因为它们操作的是当前线程持有的对象监视器锁(monitor lock)。
wait(): 使当前线程进入等待状态,并释放持有的对象锁,直到其他线程调用此对象的notify()或notifyAll()方法将其唤醒。
notify(): 随机唤醒一个正在此对象监视器上等待的单个线程。
notifyAll(): 唤醒所有正在此对象监视器上等待的线程。
// 线程A等待
synchronized(obj){
obj.wait();
}
// 线程B唤醒
synchronized(obj){
obj.notify();
}
wait(long timeout), wait(long timeout, int nanos)
这是wait()方法的重载版本,允许线程进行限时等待。调用后,线程将进入等待状态,直到以下两种情况之一发生:1)被其他线程notify唤醒;2)等待时间超过指定的毫秒数(及纳秒数)。
synchronized(obj){
obj.wait(1000); // 最多等待1秒
}
理解并掌握以上Object类的方法,是每一位Java开发者构建扎实知识体系的必经之路。它们频繁出现在日常编码和面试考察中,深入理解其原理与使用场景,能帮助你写出更高效、更稳定的程序。