追根溯源,所有的java类都是Oject的子类,那么要进一步了解java,那么去探索Object类的源码就是不可避免的。这个神秘的Oject类里面是什么东东呢?
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) throwsInterruptedException {
if (timeout < 0) {
throw new IllegalArgumentException("timeout value isnegative");
}
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源码,首先令我惊奇的是上帝类中居然一个成员属性都没有,我之前还以为最根源的类应该会存在很多属性成员来进行一些开关控制之类的功能。可见整个java设计的简洁性。下面就开始解剖Object的每一行代码了:
private static native voidregisterNatives();
static {
registerNatives();
}
上述代码首先声明了一个本地方法registerNatives,然后在静态初始化块中调用该静态方法,根据名字貌似是注册信息的方法。并且在第一次new对象时进行调用,后面再new新对象不会再重复调用。主要作用就算把C/C++的函数映射到java虚拟机的native方法中,具体是什么样的机制要后续去了解下native(本地)方法的一些知识点。
补充:
在OpenJDK源码中,可以看到有一份文件1里包含着registerNatives()
的实现:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
native方法在JNI中根据类路径添加了前缀。比如:java.lang.Object.registerNatives被命名为Java_java_lang_Object_registerNatives。可以看到除了getClass方法外,其余所有Object类的native方法都经由registerNatives进行注册。registerNatives()
在java.lang.Object中,经由static块进行调用,确保所有方法在一开始就进行加载。
如果需要在JNI中重新绑定native方法或者注册新的方法,同样可以改写JDK底层的native方法的实现。
public final native Class<?>getClass();
获取Object引用运行时的类对象,Class<T>是个模板类,这个方法返回的是Class<实际类型> 的对象,也称为类对象。比如String的类对象的类型是Class<String>,String的类对象保存着包,类名称等信息。这里需要注意的一点是类对象的类型和类不是一回事。
public native int hashCode();
对于上帝类而言,返回的是该对象的内存地址,其他子类可以重写该方法,那么就不再是返回对象的内存地址,比如String的hashcode方法就重写成下面代码
public inthashCode() {
int h = hash;
if (h == 0 &&value.length> 0) {
charval[] = value;
for (inti = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
returnh;
}
这是个乘法哈希算法。
public boolean equals(Object obj) {
return (this == obj);
}
对于上帝类而言,比较的是两个对象的地址值是否相等,子类一般根据需要重写该方法。比如String 的重写代码
public booleanequals(Object anObject){
if (this ==anObject) {
return true;
}
if (anObjectinstanceofString) {
String anotherString = (String)anObject;
intn = value.length;
if (n ==anotherString.value.length) {
charv1[] = value;
charv2[] = anotherString.value;
inti = 0;
while (n-- != 0) {
if (v1[i] !=v2[i])
returnfalse;
i++;
}
returntrue;
}
}
return false;
}
String的equals方法比较的是字符串中每个字符是否相等。
小结一下:hashCode()和equals()方法是经常被子类重写的,尤其是对于要加入hash容器的类型而言,需要非常注意这两个方法的重写。