文档

Java™ 教程-Java Tutorials 中文版
Object 作为超类
Trail: Learning the Java Language
Lesson: Interfaces and Inheritance
Section: Inheritance

Object 作为超类

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

Object 的 notify, notifyAll 和 wait 方法都在一个程序中同步独立运行的线程的活动中起作用,将在后面的课程中讨论,这里不会涉及。这些方法有五种:


注意: 许多方法都有一些微妙的方面,尤其是 clone 方法。

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 的克隆,以便对象及其克隆真正独立。

equals() 方法

equals() 方法比较两个对象是否相等,如果它们相等则返回 true。Object 类中提供的 equals() 方法使用相等运算符(==)来确定两个对象是否相等。对于基本数据类型,这会给出正确的结果。但是,对于对象,它没有。Object 提供的 equals() 方法测试对象 references (引用) 是否相等 — 也就是说,比较的对象是否是完全相同的对象。

要测试两个对象在 equivalency (等价)(包含相同信息)的意义上是否相等,必须覆盖 equals() 方法。以下是覆盖 equals() 的 Book 类的示例:

public class Book {
    ...
    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 引用两个不同的对象,此程序仍显示 objects are equal。它们被认为是相同的,因为比较的对象包含相同的 ISBN 号。

如果相等运算符不适合你的类,则应始终覆盖 equals() 方法。


注意: 如果覆盖 equals(),则还必须覆盖 hashCode()。

finalize() 方法

Object 类提供了一个回调方法 finalize(),当对象变为垃圾时,可能 调用。Object 的 finalize() 的实现什么都没做 — 你可以覆盖 finalize() 进行清理,例如释放资源。

finalize() 方法 可能由系统自动调用,但是它何时被调用,或者它是否被调用,是不确定的。因此,你不应该依赖此方法为你进行清理。例如,如果在执行 I/O 后未在代码中关闭文件描述符,并且希望 finalize() 为你关闭它们,则可能会 run out of 文件描述符。

getClass() 方法

你无法覆盖 getClass。

getClass() 方法返回一个 Class 对象,该对象具有可用于获取有关类的信息的方法,例如其名称(getSimpleName()),它的超类(getSuperclass()),以及它实现的接口(getInterfaces())。例如,以下方法获取并显示对象的类名:

void printClassName(Object obj) {
    System.out.println("The object's" + " class is " +
        obj.getClass().getSimpleName());
}

java.lang 包中的 Class 类具有大量方法(超过 50 个)。例如,你可以测试该类是否为注解(isAnnotation()),接口(isInterface())或枚举(isEnum())。你可以看到对象的字段是什么(getFields())或其方法是什么(getMethods())等等。

hashCode() 方法

hashCode() 返回的值是对象的哈希码,它是十六进制的对象的内存地址。

根据定义,如果两个对象相等,则它们的哈希码 必须也 相等。如果覆盖 equals() 方法,更改两个对象的等效方式,则 Object 的 hashCode() 的实现不再有效。因此,如果覆盖 equals() 方法,则还必须覆盖 hashCode() 方法。

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

Previous page: Using the Keyword super
Next page: Writing Final Classes and Methods