Object类解析
好久没来写。最近看到同学也在写,也跟着一起做共同撰稿人。顺便把我在那边发表的文章也挂到这边。看来写Blog也要一起写才有动力哟 。。。
为了更好地了解JAVA,使用JAVA,个人认为学习JAVA类库是会有很大帮助的。限于个人水平,仅在此抛玉引砖,望大家不吝赐教。对于本地方法的调用,在本人研究之后再补上。[separator]
这里使用的源代码为Eclipse 3.2.2自带的。猜测应该是Java5的源代码,也有可能是Java6啦,没仔细找。
第一次我们就先看看始祖类.
public class Object {
/**
* 为了能调用本地方法。 */
private static native void registerNatives();
static {
registerNatives();
}
/**
* 取得实例的类型。"所有对象都是Object的子类"这句现在应该没有人说了。Class对象就不是的。不信试试if (this.getClass() instanceof Object)?
*/
public final native Class<?> getClass();
/**
* 这里用于哈希表的KEY值使用。如果用equals方法比较两个对象相等的话,那用HashCode方法返回的值也必须一样。如果HashCode返回的值一样,却不一定代表两个对象相等。推荐作法,还是如果两个对象相等的话,HashCode应该要返回相同的值。
* 记得有一次,在一个JDK5的BETA版本里,有两个不同的STRING竟然得出相同的HashCode值!真叫人汗颜,,只好叫人家换JDK去了。。正式版的JDK就没有这问题。
* 这个方法很奇怪。
* 奇怪的是:Object里的HashCode是本地方法!!返回的是在内部的地址!!(这个地址应该可以相应地转成内存地址)我们很经常地覆盖这个方法,调用的将是子类中的非本地方法。看来本地方法也可以被覆盖。
*/
public native int hashCode();
/**
* 这个方法得满足自反性,对称性与传递性。
* 默认的Object里的equals方法仅仅是在两个对象是同一对象的情况下才返回TRUE(不然Object里没有成员变量,除了地址外还可以比较什么呢?)
* 记得看了一篇BLOG,里面说:因为Object的equals方法是比较两个对象的引用的,所以所有的对象(当时特别指出的是String对象)的equals也是比较对象的引用的。他/她/它忘了这个方法是可以被子类改写的。真是误人不浅啊。
* 一般地,改了equals方法最好也更改hashCode方法。
*/
public boolean equals(Object obj) {
return (this == obj);
}
/**
* 这个方法了也真是有病。放在Object对象里,可是却不一定能用。如果不实现Cloneable接口的话,还要抛异常。
* 那不要做事就好了嘛,可是在前面又有一个native关键字,看来那个本地方法就是用来抛异常了。真是个奇怪的方法。
*/
protected native Object clone() throws CloneNotSupportedException;
/**
* 默认地显示出类名和相应的16进制哈希码。
*/
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
/**
* 多线程中用的方法。唤醒一个等待本对象监听器的一个线程。一个对象监听器只能由一个线程所拥有,也只有拥有的线程能调用这个方法(不然又要抛异常了,唉。。)。
* 一个线程拥有这个对象监听器有三个方法:
* 1、执行对象内的同步实例方法
* 2、执行一个以本对象监听器为锁的同方法体
* 3、对于Class类型的对象,执行该类的同步静态方法。
* 这个方法还是final & native的,还不让改。
*/
public final native void notify();
/**
* 与notify方法差不多,不同的是它会唤醒多个线程来一起抢对象监听器。
*/
public final native void notifyAll();
/**
* 该方法会让当前线程(这个线程也必须拥有本对象的监听器)进入等待,并且释放所有本对象的同步锁,但不会释放其他对象锁的。
* 有以下四种情况该线程被唤醒:
* 1、有线程对本对象调用notify方法,而本线程恰好被选中
* 2、有线程对本对象调用了notifyAll方法。
* 3、有线程打断了本线程。
* 4、指定的时间用完了。或者如果指定的时间为0的话,这个线程就会一直等待。
* 奇怪的是:一个线程也有可能“假醒”(spurious wakeup),即第5种情况醒来。现实中很少碰到,但程序中还是得判断一下为好。换言之,wait还是放入到循环中比较好。比如:
* synchronized (obj) {
* while (<条件不满足>)
* obj.wait(timeout);
* ... // 执行醒来后的动作
* }
* 该方法也只能被用有本对象监听器的线程调用。
* 又是一个final & native,看来很多锁的方法都是用本地方法实现的。可能是考虑性能因素吧。
*/
public final native void wait(long timeout) throws InterruptedException;
/**
* 与wait(long timeout)一样,只是加了一个纳秒(nanos)。可是从代码中看来,这个纳秒几乎没什么用:如果越界(<0 || >999999)当然抛异常,如果大于500000,则TIMEOUT上加上一秒,如果TIMEOUT本身为0,而纳秒不为0的话就加上一秒。否则对纳秒视而不见。
* 这样的方法除了会抛异常外,似乎也没干啥事,几乎没用。不过可以理解的是,JAVA本来就慢,你要精确到纳秒?没门!
*/
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 >= 500000 || (nanos != 0 && timeout == 0)) {
timeout++;
}
wait(timeout);
}
/**
* 不多说了。。
*/
public final void wait() throws InterruptedException {
wait(0);
}
/**
* 在JVM的垃圾回收器要把该对象回收时会调用且仅调用一次这个方法。如果出现异常的话,那这个回收的过程就会中断。
* 这算是个比较正常的方法定义,方法体是空的,可以由子类来填。
* 有看到其他人在这个finalize方法里把一些引用置空,不知道这个效果如何?知道的吱一声。
* 现在的垃圾回收器的机制已经很完善了,不会单纯只用引用计数器来回收对象。谁有使用过finalize方法,且让性能提高的请出来说一下。
*/
protected void finalize() throws Throwable { }
}