这篇Java教程基于JDK1.8。教程中的示例和实践不会使用未来发行版中的优化建议。
5.2.6、作为父类的Object
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()
返回对象的字符串描述
Object类中的notify,notifyAll和wait 方法在线程同步活动中发挥作用。这将在后续的教程中予以讨论,本节不包含该内容。一共有5个这样的方法:
- 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)
clone()方法
如果一个类,或者它的一个父类实现了Cloneable 接口,可以使用clone() 创建一个已有对象的拷贝。为创建拷贝,你可以:
aCloneableObject.clone();
上面的实现会检查调用clone()方法的对象是否有实现Cloneable 接口。如果没有实现,方法将抛出CloneNotSupportedException的异常。异常处理将在后续的教程中讨论。当你想重写Object类的*clone()*方法,你可以用如下的方式来声明:
protected Object clone() throws CloneNotSupportedException
或
public Object clone() throws CloneNotSupportedException
如果调用clone()方法的对象实现了Cloneable接口,Object类的*clone()*方法实现了根据原对象创建同类型的对象并根据原对象的成员变量来初始化新对象的成员变量。
让类可复制的最简单办法就是在类声明上实现Cloneable 接口。对象可以调用*clone()*方法。
对一些类来说,Object的clone()方法默认行为能工作的很好。然而,对于持有外部对象引用的对象(暂且称为ObjExternal)来说,需要重写clone()方法来获得正确的行为。否则, 对象的ObjExternal发生改变,其拷贝对象也能看到该变化。这意味着原始对象和拷贝对象没有独立开来—为了解耦,你必须重写clone()方法,拷贝该对象和ObjExternal。这样原对象引用ObjExternal,拷贝对象引用ObjExternal的拷贝,这时对象和它的拷贝之间是独立的了。
equals()方法
equals()方法比较对象的相等性,他们相等就返回true。Object类提供的equals()方法使用==来判断两个对象是否相等。对原始类型来说,这没有问题。但对对象来说,这将得到错误的结果。Object类中的equals方法验证对象引用是否相等—即比较的两个对象是否是同一个。
为验证两个对象在语义上的相等性,你必须重写equals()方法。下面是Book类重写了*equals()*方法的示例:
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");
}
程序打印 objects are equal 即使 firstBook 和 secondBook 引用了两个不同的对象。他们被认为是相等的因为拥有同样的ISBN。
当类的标识符不合适时你总是应该重写它的 equals() 方法。
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类,提供了大量的方法(超过50个)。比如你可以查看类是不是注解(isAnnotation()),是不是接口(isInterface()),是不是枚举(isEnum())。可以看到对象的字段(getFields())和对象的方法(getMethods())有哪些等等。
hashCode方法
hashCode() 方法返回的是对象的哈希码,即对象在内存中地址的十六进制表示。
从定义来说,两个对象相等,它们的哈希码必须相等。如果重写了equals()方法,改变了两个对象的比较方式,Object类的hashCode() 实现就失效了。因此,如果你重写了equals() 方法,必须重写 hashCode() 方法。
toString()方法
建议总是考虑重写 toString() 方法。
Object的 toString() 方法返回对象的字符串描述,这在调试阶段非常有用。对象的字符串描述依赖整个对象,这也是你需要重写toString() 的原因。
可以和System.out.println() 配合使用 toString() 来打印对象的文本描述,比如Book实例:
System.out.println(firstBook.toString());
因为重写了toString() 方法,将会打印非常有用的信息,如下:
ISBN: 0201914670; The Swing Tutorial; A Guide to Constructing GUIs, 2nd Edition