JDK源码阅读(7):Object

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);
}

直接对两个对象用 == 进行比较,比较的为其内存地址,但在很多的时候判断两个对象是否一致,判断的是其的 “状态”(绝大多数情况是对其字段值进行比较),类似于上篇提及的 compareToObject提供了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 返回能反应对象状态的字符串,不同于hashCodetoString 更具有可读性。

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 (&lt;condition does not hold&gt;)
 *             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();

notifywait 相对应,其会唤醒在该对象上等待的线程,使得其结束等待。
notify() 将会唤醒一个线程,notifyAll() 将会唤醒所有在该对象上等待的线程。

当然,唤醒不代表该线程可以继续执行,线程接下来要获取到该对象的锁才能继续执行。

Object类还有最后一段代码:

private static native void registerNatives();
static {
    registerNatives();
}

由名字推测,该段代码注册类中的本地方法。
博客了解到:
一个Java程序要想调用一个本地方法,需要执行两个步骤:

  1. 通过System.loadLibrary()将包含本地方法实现的动态文件加载进内存。
  2. 虚拟机在加载的动态文件中定位并链接该本地方法,进而执行。

registerNatives()方法的作用就是取代第二步,让程序主动将本地方法链接到调用方,当Java程序需要调用本地方法时可以直接调用,提高调用效率。

当然,调用本地方法registerNatives还需要执行上述两步。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值