Object
version:1.8
java.lang.Object是Java所有类的父类,可以说是JDK源码的“根”
package java.lang;
public class Object {
…………
}
先看看其全貌:
finalize
每个对象在构造时可能需要做些准备工作,这就是每个类的构造方法,同样的,在析构前可能要做些善后工作,对应的方法就是finalize
protected void finalize() throws Throwable { }
Object类的该方法是空实现,为子类的重写做准备。
由于JVM垃圾回收时间等的不确定性,程序编写的准确性不应依赖于finalize的编写。
equals
public boolean equals(Object obj) {
return (this == obj);
}
直接对两个对象用 == 进行比较,比较的为其内存地址,但在很多的时候判断两个对象是否一致,判断的是其的 “状态”(绝大多数情况是对其字段值进行比较),类似于上篇提及的 compareTo,Object提供了equals方法,默认实现还是比较内存地址,需要子类重写。
getClass
public final native Class<?> getClass();
每一个类具有字段名,方法,实现的接口,静态变量等类持有的信息,这些存储在JVM的方法区(永久代,现在替换为元空间),JVM为每一个类提供一个Class对象(存储在堆中)以使得Java程序可操作这些信息(反射),通过getClass可获得对象对应类的Class对象。
该方法使用native关键字,代表该方法使用C语言等其他语言编写。
hashCode
/**
* <li>If two objects are equal according to the {@code equals(Object)}
* method, then calling the {@code hashCode} method on each of
* the two objects must produce the same integer result.
*/
public native int hashCode();
该方法在HashMap中看到过,作用就是对对象状态进行散列,得到一个整数值。
由注释可以得知,若两个对象通过equals判断相等,其产生的哈希值应该相同,但反之并不一定,即哈希值相同,但equals判断不一定相等。
默认实现返回的为对象的地址。
toString
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
与hashCode类似,toString 返回能反应对象状态的字符串,不同于hashCode,toString 更具有可读性。
clone
/**
* @throws CloneNotSupportedException if the object's class does not
* support the {@code Cloneable} interface. Subclasses
* that override the {@code clone} method can also
* throw this exception to indicate that an instance cannot
* be cloned.
*/
protected native Object clone() throws CloneNotSupportedException;
public interface Cloneable {
}
直接将一个引用赋给另一个引用,两个引用指向的其实是一个对象,为了获得一个与当前对象状态相同的新的对象,就需要调用clone方法。
但为了调用该方法,类应该实现接口Cloneable,该接口并没有定义任何方法,仅仅是一个标记。
思考原因:该方法的默认实现仅仅是将对象各字段的值进行拷贝,基本数据类型的拷贝自然没有问题,但引用值的拷贝正如上述,其实指向的是同一个对象(浅拷贝),由此程序可能会造成问题。故调用该方法默认实现存在风险,类标记该接口,代表该类已重写clone方法,将浅拷贝改为深拷贝,或者并不存在浅拷贝的问题,可放心调用clone方法。
wait
/*
* @param timeout the maximum time to wait in milliseconds.
* @throws IllegalArgumentException if the value of timeout is
* negative.
* @throws IllegalMonitorStateException if the current thread is not
* the owner of the object's monitor.
* @throws InterruptedException if any thread interrupted the
* current thread before or while the current thread
* was waiting for a notification. The <i>interrupted
* status</i> of the current thread is cleared when
* this exception is thrown.
*/
public final native void wait(long timeout) throws InterruptedException;
public final void wait() throws InterruptedException {
wait(0);
}
public final void wait(long timeout, int nanos) throws InterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (nanos < 0 || nanos > 999999) {
throw new IllegalArgumentException(
"nanosecond timeout value out of range");
}
if (nanos > 0) {
timeout++;
}
wait(timeout);
}
/*
* synchronized (obj) {
* while (<condition does not hold>)
* obj.wait(timeout);
* ... // Perform action appropriate to condition
* }
*/
wait 方法应用于多线程中的调度。
Java每个对象都可以作为一个锁应用于 synchronized块,调用该方法的线程会释放持有的锁(对象)并等待。
等待过程可被中断,触发InterruptedException异常。
等待可设置最长等待时长,单位ms,结束后一般需要判断是否满足条件,否则重新等待,正如上文实例。
需要注意,时间到(或被中断)不一定会立刻结束等待,此时还需要获取到所需的锁才能够返回。
虽然提供了纳秒级别的方法的重写,但正如源码所示,仅仅毫秒加1,并未真正提供到纳秒精度。
notify
public final native void notify();
public final native void notifyAll();
notify与wait 相对应,其会唤醒在该对象上等待的线程,使得其结束等待。
notify() 将会唤醒一个线程,notifyAll() 将会唤醒所有在该对象上等待的线程。
当然,唤醒不代表该线程可以继续执行,线程接下来要获取到该对象的锁才能继续执行。
Object类还有最后一段代码:
private static native void registerNatives();
static {
registerNatives();
}
由名字推测,该段代码注册类中的本地方法。
由博客了解到:
一个Java程序要想调用一个本地方法,需要执行两个步骤:
- 通过System.loadLibrary()将包含本地方法实现的动态文件加载进内存。
- 虚拟机在加载的动态文件中定位并链接该本地方法,进而执行。
registerNatives()方法的作用就是取代第二步,让程序主动将本地方法链接到调用方,当Java程序需要调用本地方法时可以直接调用,提高调用效率。
当然,调用本地方法registerNatives还需要执行上述两步。