JDK1.8源码阅读笔记(1)Object类
Object 类属于 java.lang 包,此包下的所有类在使⽤时⽆需⼿动导⼊,系统会在程序编译期间⾃动 导⼊。Object 类是所有类的基类,当⼀个类没有直接继承某个类时,默认继承Object类,也就是说任何 类都直接或间接继承此类,Object 类中能访问的⽅法在所有类中都可以调⽤。
Object类源码:
native关键字
Java有两种方法:Java方法和本地方法。Java方法是由Java语言编写,编译成字节码,存储在class文件中。本地方法是由其他语言(比如C,C++,或者汇编)编写的,编译成和处理器相关的机器代码。本地方法保存在动态连接库中,格式是各个平台专有的。Java方法是平台无关的,单本地方法却不是。运行中的Java程序调用本地方法时,虚拟机装载包含这个本地方法的动态库,并调用这个方法。本地方法是联系Java程序和底层主机操作系统的连接方法
被native关键字修饰的方法叫做本地方法,简单地讲,一个native方法就是一个java调用非java代码的接口。一个Native Method是这样一个java的方法:该方法的实现由非java语言实现,比如C。另外native方法在JVM中运行时数据区也和其它方法不一样,它有专门的本地方法栈。
Object类源码
package java.lang;
public class Object {
private static native void registerNatives();
static {
registerNatives();
}
public final native Class<?> getClass();
public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
}
protected native Object clone() throws CloneNotSupportedException;
public String toString() {
return getClass().getName() + "@" +Integer.toHexString(hashCode());
}
public final native void notify();
public final native void notifyAll();
public final native void wait(long timeout) throws InterruptedException;
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);
}
public final void wait() throws InterruptedException {
wait(0);
}
protected void finalize() throws Throwable { }
}
Object类中的12个方法
clone
clone方法可以完成对象的浅克隆。所谓浅克隆就是说被克隆的对象的各个属性都是基本类型,而不是引用类型(接口、类、数组),如果存在引用类型的属性,则需要进行深克隆。要想实现 Address的深克隆,首先让Address类实现 Cloneable 接口,重写clone方法。
之前的文章中写过clone方法与深拷贝浅拷贝:Java clone() 方法克隆对象——深拷贝与浅拷贝
protected native Object clone() throws CloneNotSupportedException;
equals
在引用类型中,"=="是比较两个引用是否指向堆内存里的同一个地址(同一个对象),而equals是一个普通的方法,该方法返回的结果依赖于自身的实现。要比较两个对象的内容是否相同,需要重写该方法。
public boolean equals(Object obj) {
return (this == obj);
}
finalize
finalize()是Object的protected方法,子类可以覆盖该方法以实现资源清理工作,GC在回收对象之前调用该方法,当对象变成(GC Roots)不可达时,GC会判断该对象是否覆盖了finalize方法,若未覆盖,则直接将其回收。否则,若对象未执行过finalize方法,将其放入F-Queue队列,由一低优先级线程执行该队列中对象的finalize方法。执行finalize方法完毕后,GC会再次判断该对象是否可达,若不可达,则进行回收,否则,对象“复活”。
protected void finalize() throws Throwable { }
getClass
Class是一个实实在在的类,在包 java.lang 下,有一个Class.java文件,它跟我们自己定义的类一样,是一个实实在在的类,Class对象就是这个Class类的实例。在Java里,所有的类的根源都是Object类,而Class也不例外,它是继承自Object的一个特殊的类,它内部可以记录类的成员、接口等信息,也就是在Java里,Class是一个用来表示类的类。
public final native Class<?> getClass();
registerNatives
在Object类中,除了有registerNatives这个本地方法之外,还有hashCode()、clone()等本地方法,而在Class类中有forName()这样的本地方法等等。也就是说,凡是包含registerNatives()本地方法的类,同时也包含了其他本地方法。所以,显然,当包含registerNatives()方法的类被加载的时候,注册的方法就是该类所包含的除了registerNatives()方法以外的所有本地方法。使用native方法的好处:
- 通过registerNatives方法在类被加载的时候就主动将本地方法链接到调用方,比当方法被使用时再由虚拟机来定位和链接更方便有效;
- 如果本地方法在程序运行中更新了,可以通过调用registerNative方法进行更新;
- Java程序需要调用一个本地应用提供的方法时,因为虚拟机只会检索本地动态库,因而虚拟机是无法定位到本地方法实现的,这个时候就只能使用registerNatives()方法进行主动链接。
registerNatives是⽤ private 关键字声明的,在类外⾯根本调⽤不了。静态代码块就是⼀个类在初始化过程中必定会执⾏的内容,所以在类加载的时候是会执⾏该⽅法的,通过该⽅法来注册本地⽅法。
private static native void registerNatives();
static {
registerNatives();
}
hashCode
hashCode就是对象的散列码,是根据对象的某些信息推导出的一个整数值,默认情况下表示是对象的存储地址。通过散列码,可以提高检索的效率,主要用于在散列存储结构中快速确定对象的存储地址,如Hashtable、hashMap中。
wait notify notifyAll
这三个方法最终调用的都是jvm级的final native方法
- 如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。
- 如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。
- 如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。
其中wait方法有三个over load方法:
- wait()
- wait(long)
- wait(long,int)
wait方法通过参数可以指定等待的时长。如果没有指定参数,默认一直等待直到被通知。
toString()
getClass().getName()是返回对象的全类名(包含包名),Integer.toHexString(hashCode()) 是以16进制⽆符号整数形式返回此哈希码的字符串表示形式。打印某个对象时,默认是调⽤ toString ⽅法,⽐如 System.out.println(object),等价于System.out.println(object.toString())。
public String toString() {
return getClass().getName() + "@" +Integer.toHexString(hashCode());
}