# Object 作为超类

Object 在 java.lang 包,坐镇类层次结构树的顶端。每个阶级都是 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()

    返回对象的字符串表示形式。

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)

TIP

这些方法中有一些细微的方面,尤其是 clone 方法。

# clone() 方法

如果某个类或其某个超类实现了该 Cloneable 接口,则可以使用该 clone() 方法从现有对象创建一个副本。要创建一个克隆,你写:

aCloneableObject.clone();
1

Object 这个方法的实现将检查 clone() 被调用的对象是否实现了 Cloneable 接口。如果该对象没有,该方法抛出一个 CloneNotSupportedException 异常。异常处理将在后面的课程中介绍。目前,您需要知道 clone() 必须声明为

protected Object clone() throws CloneNotSupportedException

or:

public Object clone() throws CloneNotSupportedException
1
2
3
4
5

如果你打算写一个 clone() 方法来覆盖 Object。

如果 clone() 被调用的对象确实实现了 Cloneable 接口,则 Object 的 clone() 方法的实现将创建与原始对象相同类的对象,并将新对象的成员变量初始化为与原始对象的相应成员变量具有相同的值。

使类可复制的最简单的方法是添加 implements Cloneable 到类的声明中。那么你的对象可以调用 clone() 方法。

对于一些类,默认行为 Object 的 clone() 方法工作得很好。但是,如果某个对象包含对外部对象的引用,则可能需要重写 clone() 才能获得正确的行为。否则,外部引用对象所做的更改也将在克隆中可见。这意味着原始对象和它的克隆不是独立的,要解耦他们,必须重写。连引用的外部对象也需要克隆,以便该对象和它的克隆是真正独立的。

# equals 方法

equals 方法比较两个对象是否相等,如果返回 true 则相等。Object 中提供的 equals 方法使用 「==」 来确定两个对象是否相等,对于原始数据类型,这给出了正确的结果。然而,对于对象来说,事实并非如此。

为了测试两个包含相同信息的对象是否相等。必须重写 equals 方法。这里是一个例子

public class Book {
    ...
    public boolean equals(Object obj) {
        if (obj instanceof Book)
            return ISBN.equals((Book)obj.getISBN());
        else
            return false;
    }
}
1
2
3
4
5
6
7
8
9

考虑这个测试 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");
}
1
2
3
4
5
6
7
8

即使 firstBook 和 secondBook 引用不同的对象。它们被认为是相等的,因为比较的对象包含相同的 ISBN 号码。

如果 equals 默认的运算不符合你的类,则应该始始终重写该方法

TIP

注意:如果您重写 equals(),您也必须重写 hashCode()

# finalize 方法

Object 类提供的回调方法,当对象变成垃圾时,该方法被回调。Object 的 finalize() 什么都不做,你可以覆盖 finalize() 做清理工作,比如释放资源。

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

# getClass 方法

你不能覆盖 getClass。

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

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

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

# hashCode 方法

hashCode() 方法返回的值是对象的哈希码,它是以十六进制表示的对象的内存地址。根据定义,如果两个对象相等,则它们的哈希码也 必须相等。如果你重写了这个 equals() 方法,你就改变了两个对象的等同方式,而且其 Object 的 hashCode() 不再有效。因此,如果您重写 equals() 方法,则还必须重写该 hashCode() 方法。

# toString 方法

你的类中应该总是考虑重写 toString() 方法。

所述 Object 的 toString() 方法返回 String 的对象,这是对于调试非常有用的表示。String 对象的表示完全取决于对象,这就是为什么你需要在你的类中重写 toString()

您可以使用 System.out.println() 来显示 toString() 的内容(对象的文本表示形式),例如:

System.out.println(firstBook.toString());
1

这对于一个正确的重写 toString()方法来说,可以打印一些有用的东西,比如:

ISBN:0201914670; Swing教程; 构建GUI的指南,第2
1