系列中的上一篇
当前教程
对象作为超类
系列中的下一篇

系列中的上一篇: 多态

系列中的下一篇: 抽象方法和类

对象作为超类

 

来自 Object 类的的方法

Object 类位于 java.lang 包的类层次结构树的顶端。每个类都是 Object 类的直接或间接后代。您使用的或编写的每个类都继承了 Object 的实例方法。您无需使用这些方法中的任何一个,但是,如果您选择这样做,您可能需要使用特定于您类的代码覆盖它们。本节中讨论的从 Object 继承的方法是

请注意,从 Java SE 9 开始,finalize() 方法已弃用,从 Java SE 18 开始,已弃用并将在将来移除。强烈建议不要覆盖此方法。在某个时候,它将不再被调用。有关更多信息,请参阅 本页的最后一节

Object 的 notify()notifyAll()wait() 方法都在程序中独立运行的线程的活动同步中发挥作用,这将在后面的部分中讨论,这里将不再介绍。这些方法共有五个

注意:这些方法中的一些方法有一些细微之处,尤其是 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");
}

该程序显示对象相等,即使 firstBooksecondBook 引用了两个不同的对象。它们被认为是相等的,因为比较的对象包含相同的 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 接口,Objectclone() 方法的实现会创建一个与原始对象相同类别的对象,并将新对象的成员变量初始化为与原始对象对应成员变量相同的值。

使您的类可克隆的最简单方法是在类声明中添加 implements Cloneable。然后您的对象可以调用 clone() 方法。

对于某些类,Objectclone() 方法的默认行为就足够了。但是,如果一个对象包含对外部对象的引用,例如 ObjExternal,您可能需要覆盖 clone() 以获得正确的行为。否则,一个对象对 ObjExternal 的更改也会在它的克隆中可见。这意味着原始对象及其克隆不是独立的——为了将它们分离,您必须覆盖 clone(),以便它克隆对象和 ObjExternal。然后原始对象引用 ObjExternal,克隆对象引用 ObjExternal 的克隆,这样对象及其克隆就真正独立了。

 

finalize() 方法

Object 类提供了一个回调方法,finalize(),当对象成为垃圾时可能会在该对象上调用。Objectfinalize() 的实现什么也不做。覆盖 finalize() 是为了进行一些清理工作,例如释放资源。

finalize() 方法可能会由系统自动调用,但何时调用,甚至是否调用都是不确定的。因此,您不应该再依赖此方法来为您进行清理。例如,如果您在执行 I/O 后没有在代码中关闭文件描述符,并且您期望 finalize() 为您关闭它们,您可能会用完文件描述符。

从 Java SE 9 开始,finalize() 方法已被弃用,从 Java SE 18 开始,被弃用以供移除。在某个时刻,它将不再被调用。现在强烈建议不要覆盖此方法。如果您需要清理一些资源,您可以通过实现 AutoCloseable 接口来完成。这一点将在 Java I/O 部分 中详细介绍。


最后更新: 2021 年 9 月 14 日


系列中的上一篇
当前教程
对象作为超类
系列中的下一篇

系列中的上一篇: 多态

系列中的下一篇: 抽象方法和类