# 对象作为超类

> 原文： [https://docs.oracle.com/javase/tutorial/java/IandI/objectclass.html](https://docs.oracle.com/javase/tutorial/java/IandI/objectclass.html)

`java.lang`包中的 [`Object`](https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html) 类位于类层次结构树的顶部。每个类都是`Object`类的后代，直接或间接的。您使用或编写的每个类都继承`Object`的实例方法。您不需要使用任何这些方法，但是，如果您选择这样做，则可能需要使用特定于您的类的代码覆盖它们。本节中讨论的从`Object`继承的方法是：

*   `protected Object clone() throws CloneNotSupportedException`
    创建并返回此对象的副本。
*   `public boolean equals(Object obj)`
    指示某个其他对象是否“等于”此对象。
*   `protected void finalize() throws Throwable`
    当垃圾
    集合确定没有对该对象的更多引用时，由对象上的垃圾收集器调用
*   `public final Class getClass()`
    返回对象的运行时类。
*   `public int hashCode()`
    返回对象的哈希码值。
*   `public String toString()`
    返回对象的字符串表示形式。

`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)`

* * *

**Note:** There are some subtle aspects to a number of these methods, especially the `clone` method.

* * *

## 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()`方法测试对象 _ 引用 _ 是否相等 - 即，如果比较的对象是完全相同的对象。

要测试两个对象在 _ 等效性 _（包含相同信息）的意义上是否相等，必须覆盖`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()`方法。

* * *

**Note:** If you override `equals()`, you must override `hashCode()` as well.

* * *

## finalize（）方法

`Object`类提供了一个回调方法`finalize()`，当它变为垃圾时，_ 可能会在对象上调用 _。 `Object` `finalize()`的实现没有做任何事情 - 您可以覆盖`finalize()`进行清理，例如释放资源。

`finalize()`方法 _ 可以是系统自动调用的 _，但是当它被调用时，或者即使它被调用，也是不确定的。因此，您不应该依赖此方法为您进行清理。例如，如果在执行 I / O 后没有在代码中关闭文件描述符，并且您希望`finalize()`为您关闭它们，则可能会用完文件描述符。

## 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`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html) 类有很多方法（超过 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

```