对象作为超类
来自 Object 类的的方法
Object 类位于 java.lang
包的类层次结构树的顶端。每个类都是 Object
类的直接或间接后代。您使用的或编写的每个类都继承了 Object
的实例方法。您无需使用这些方法中的任何一个,但是,如果您选择这样做,您可能需要使用特定于您类的代码覆盖它们。本节中讨论的从 Object
继承的方法是
protected Object clone() throws CloneNotSupportedException
: 创建并返回此对象的副本。public boolean equals(Object obj)
: 指示某个其他对象是否“等于”此对象。protected void finalize() throws Throwable
: 当垃圾收集确定不再有对该对象的引用时,由垃圾收集器在对象上调用。从 Java 18 开始,此方法已弃用,将在将来移除。public final Class getClass()
: 返回对象的运行时类。public int hashCode()
: 返回对象的哈希码值。public String toString()
: 返回对象的字符串表示形式。
请注意,从 Java SE 9 开始,finalize()
方法已弃用,从 Java SE 18 开始,已弃用并将在将来移除。强烈建议不要覆盖此方法。在某个时候,它将不再被调用。有关更多信息,请参阅 本页的最后一节。
Object 的 notify()
、notifyAll()
和 wait()
方法都在程序中独立运行的线程的活动同步中发挥作用,这将在后面的部分中讨论,这里将不再介绍。这些方法共有五个
public final void notify()
public final void notifyAll()
public final void wait()
public final void wait(long timeout)
public final void wait(long timeout, int nanos)
注意:这些方法中的一些方法有一些细微之处,尤其是 clone 方法。
toString() 方法
您应该始终考虑在您的类中覆盖 toString()
方法。
Object 的 toString()
方法返回对象的 String
表示形式,这对于调试非常有用。对象的 String
表示形式完全取决于对象,这就是您需要在您的类中覆盖 toString()
的原因。
您可以使用 toString()
以及 System.out.println()
来显示对象的文本表示形式,例如 Book
的实例
System.out.println(firstBook.toString());
对于正确覆盖的 toString()
方法,这将打印一些有用的内容,如下所示
ISBN: 0201914670; The Swing Tutorial; A Guide to Constructing GUIs, 2nd Edition
equals() 方法
equals()
方法比较两个对象以确定是否相等,如果相等则返回 true。Object 类中提供的 equals()
方法使用标识运算符 (==
) 来确定两个对象是否相等。对于基本数据类型,这会给出正确的结果。但是,对于对象,则不会。Object 提供的 equals()
方法测试对象引用是否相等,即比较的对象是否完全是同一个对象。
要测试两个对象在等效性意义上是否相等(包含相同的信息),您必须覆盖 equals()
方法。以下是一个覆盖 equals()
的 Book
类的示例
public class Book {
String ISBN;
public String getISBN() {
return ISBN;
}
public boolean equals(Object obj) {
if (obj instanceof Book)
return ISBN.equals((Book)obj.getISBN());
else
return false;
}
}
考虑以下测试 Book
类的两个实例是否相等的代码
// Swing Tutorial, 2nd edition
Book firstBook = new Book("0201914670");
Book secondBook = new Book("0201914670");
if (firstBook.equals(secondBook)) {
System.out.println("objects are equal");
} else {
System.out.println("objects are not equal");
}
该程序显示对象相等,即使 firstBook
和 secondBook
引用了两个不同的对象。它们被认为是相等的,因为比较的对象包含相同的 ISBN 号码。
如果标识运算符不适合您的类,您应该始终覆盖 equals()
方法。
注意:如果您覆盖
equals()
,您也必须覆盖hashCode()
。
hashCode() 方法
hashCode()
返回的值是对象的哈希码,它是通过哈希算法生成的整数值。
根据定义,如果两个对象相等,它们的哈希码也必须相等。如果您覆盖 equals()
方法,您将更改两个对象相等的方式,并且 Object 的 hashCode()
实现将不再有效。因此,如果您覆盖 equals()
方法,您也必须覆盖 hashCode()
方法。
getClass() 方法
您不能覆盖 getClass()
。
getClass()
方法返回一个 Class
对象,该对象具有可用于获取有关该类信息的方法,例如其名称 (getSimpleName()
)、其超类 (getSuperclass()
) 以及它实现的接口 (getInterfaces()
)。例如,以下方法获取并显示对象的类名
void printClassName(Object obj) {
System.out.println("The object's" + " class is " +
obj.getClass().getSimpleName());
}
Class
类位于 java.lang
包中,具有大量方法(超过 50 个)。例如,您可以测试该类是否为注释 (isAnnotation()
)、接口 (isInterface()
) 或枚举 (isEnum()
)。您可以查看对象的字段是什么 (getFields()
) 或它的方法是什么 (getMethods()
) 等等。
clone() 方法
如果一个类或其超类之一实现了 Cloneable
接口,您可以使用 clone()
方法从现有对象创建副本。要创建克隆,您需要编写
aCloneableObject.clone();
Object
对该方法的实现会检查调用 clone()
的对象是否实现了 Cloneable
接口。如果对象没有实现该接口,该方法会抛出一个 CloneNotSupportedException
异常。异常处理将在 异常 部分介绍。目前,您需要知道 clone()
必须声明为
protected Object clone() throws CloneNotSupportedException
或
public Object clone() throws CloneNotSupportedException
如果您要编写一个 clone()
方法来覆盖 Object
中的方法。
如果调用 clone()
的对象确实实现了 Cloneable
接口,Object
对 clone()
方法的实现会创建一个与原始对象相同类别的对象,并将新对象的成员变量初始化为与原始对象对应成员变量相同的值。
使您的类可克隆的最简单方法是在类声明中添加 implements
Cloneable
。然后您的对象可以调用 clone()
方法。
对于某些类,Object
的 clone()
方法的默认行为就足够了。但是,如果一个对象包含对外部对象的引用,例如 ObjExternal
,您可能需要覆盖 clone()
以获得正确的行为。否则,一个对象对 ObjExternal
的更改也会在它的克隆中可见。这意味着原始对象及其克隆不是独立的——为了将它们分离,您必须覆盖 clone()
,以便它克隆对象和 ObjExternal
。然后原始对象引用 ObjExternal
,克隆对象引用 ObjExternal
的克隆,这样对象及其克隆就真正独立了。
finalize()
方法
Object
类提供了一个回调方法,finalize()
,当对象成为垃圾时可能会在该对象上调用。Object
对 finalize()
的实现什么也不做。覆盖 finalize()
是为了进行一些清理工作,例如释放资源。
finalize()
方法可能会由系统自动调用,但何时调用,甚至是否调用都是不确定的。因此,您不应该再依赖此方法来为您进行清理。例如,如果您在执行 I/O 后没有在代码中关闭文件描述符,并且您期望 finalize()
为您关闭它们,您可能会用完文件描述符。
从 Java SE 9 开始,finalize()
方法已被弃用,从 Java SE 18 开始,被弃用以供移除。在某个时刻,它将不再被调用。现在强烈建议不要覆盖此方法。如果您需要清理一些资源,您可以通过实现 AutoCloseable
接口来完成。这一点将在 Java I/O 部分 中详细介绍。
最后更新: 2021 年 9 月 14 日