对象作为超类

原文: https://docs.oracle.com/javase/tutorial/java/IandI/objectclass.html

java.lang包中的 Object 类位于类层次结构树的顶部。每个类都是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() 返回对象的字符串表示形式。

ObjectnotifynotifyAllwait方法都在同步程序中独立运行的线程的活动中起作用,这将在后面的课程中讨论,这里不再介绍。这些方法有五种:

  • 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()方法从现有对象创建副本。要创建克隆,请编写:

  1. aCloneableObject.clone();

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

  1. protected Object clone() throws CloneNotSupportedException

要么:

  1. public Object clone() throws CloneNotSupportedException

如果你打算用clone()方法来覆盖Object中的那个。

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

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

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

equals()方法

equals()方法比较两个对象是否相等,如果它们相等则返回trueObject类中提供的equals()方法使用标识运算符(==)来确定两个对象是否相等。对于原始数据类型,这会给出正确的结果。但是,对于对象,它没有。 Object提供的equals()方法测试对象引用是否相等 - 即,如果比较的对象是完全相同的对象。

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

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

考虑这个代码来测试Book类的两个实例是否相等:

  1. // Swing Tutorial, 2nd edition
  2. Book firstBook = new Book("0201914670");
  3. Book secondBook = new Book("0201914670");
  4. if (firstBook.equals(secondBook)) {
  5. System.out.println("objects are equal");
  6. } else {
  7. System.out.println("objects are not equal");
  8. }

即使firstBooksecondBook引用两个不同的对象,该程序也会显示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())。例如,以下方法获取并显示对象的类名称:

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

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

hashCode()方法

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

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

toString()方法

您应该始终考虑覆盖类中的toString()方法。

ObjecttoString()方法返回对象的String表示,这对于调试非常有用。对象的String表示完全取决于对象,这就是您需要在类中重写toString()的原因。

您可以使用toString()System.out.println()显示对象的文本表示,例如Book的实例:

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

对于正确覆盖的toString()方法,它会打印一些有用的东西,如下所示:

  1. ISBN: 0201914670; The Swing Tutorial; A Guide to Constructing GUIs, 2nd Edition