Java从JDK源码角度对Object进行实例分析
|
Object是所有类的父类,也就是说java中所有的类都是直接或者间接继承自Object类。比如你随便创建一个classA,虽然没有明说,但默认是extendsObject的。 后面的三个点"..."表示可以接受若干不确定数量的参数。老的写法是Objectargs[]这样,但新版本的java中推荐使用...来表示。例如
object是java中所有类的父类,也就是说所有的类,不管是自己创建的类还是系统中的类都继承自object类,也就是说所有的类在任何场合都可以代替object类,根据里氏替换原则,子类在任何场合都可以代替其父类,而父类却不一定能代替其子类,java中常说的万物皆对象说的其实就是这个道理!object类体现了oop思想中的多态,继承,封装,抽象四大特性! object类是所有类的基类,不是数据类型。这个你可以查询jdk文档了解,所有类都继承自Object。 Object...objects这种参数定义是在不确定方法参数的情况下的一种多态表现形式。即这个方法可以传递多个参数,这个参数的个数是不确定的。这样你在方法体中需要相应的做些处理。因为Object是基类,所以使用Object...objects这样的参数形式,允许一切继承自Object的对象作为参数。这种方法在实际中应该还是比较少用的。 Object[]obj这样的形式,就是一个Object数组构成的参数形式。说明这个方法的参数是固定的,是一个Object数组,至于这个数组中存储的元素,可以是继承自Object的所有类的对象。 这些基础东西建议你多看几遍"Thinkinjava" Java的Object是所有其他类的父类,从继承的层次来看它就是最顶层根,所以它也是唯一一个没有父类的类。它包含了对象常用的一些方法,比如getClass、hashCode、equals、clone、toString、notify、wait等常用方法。所以其他类继承了Object后就可以不用重复实现这些方法。这些方法大多数是native方法,下面具体分析。 主要的代码如下:
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 {
}
}
registerNatives方法 由于registerNatives方法被static块修饰,所以在加载Object类时就会执行该方法,对应的本地方法为Java_java_lang_Object_registerNatives,如下,
JNIEXPORT void JNICALL
Java_java_lang_Object_registerNatives(JNIEnv *env,jclass cls)
{
(*env)->RegisterNatives(env,cls,methods,sizeof(methods)/sizeof(methods[0]));
}
可以看到它间接调用了JNINativeInterface_结构体的方法,简单可以看成是这样:它干的事大概就是将Java层的方法名和本地函数对应起来,方便执行引擎在执行字节码时根据这些对应关系表来调用C/C++函数,如下面,将这些方法进行注册,执行引擎执行到hashCode方法时就可以通过关系表来查找到JVM的JVM_IHashCode函数,其中()I还可以得知Java层上的类型应该转为int类型。这个映射其实就可以看成将字符串映射到函数指针。
static JNINativeMethod methods[] = {
{"hashCode","()I",(void *)&JVM_IHashCode},{"wait","(J)V",(void *)&JVM_MonitorWait},{"notify","()V",(void *)&JVM_MonitorNotify},{"notifyAll",(void *)&JVM_MonitorNotifyAll},{"clone","()Ljava/lang/Object;",(void *)&JVM_Clone},};
getClass方法 getClass方法也是个本地方法,对应的本地方法为Java_java_lang_Object_getClass,如下:
JNIEXPORT jclass JNICALL
Java_java_lang_Object_getClass(JNIEnv *env,jobject this)
{
if (this == NULL) {
JNU_ThrowNullPointerException(env,NULL);
return 0;
} else {
return (*env)->GetObjectClass(env,this);
}
}
所以这里主要就是看GetObjectClass函数了,Java层的Class在C++层与之对应的则是klassOop,所以关于类的元数据和方法信息可以通过它获得。
JNI_ENTRY(jclass,jni_GetObjectClass(JNIEnv *env,jobject obj))
JNIWrapper("GetObjectClass");
DTRACE_PROBE2(hotspot_jni,GetObjectClass__entry,env,obj);
klassOop k = JNIHandles::resolve_non_null(obj)->klass();
jclass ret =
(jclass) JNIHandles::make_local(env,Klass::cast(k)->java_mirror());
DTRACE_PROBE1(hotspot_jni,GetObjectClass__return,ret);
return ret;
JNI_END
hashCode方法 由前面registerNatives方法将几个本地方法注册可知,hashCode方法对应的函数为JVM_IHashCode,即
JVM_ENTRY(jint,JVM_IHashCode(JNIEnv* env,jobject handle))
JVMWrapper("JVM_IHashCode");
// as implemented in the classic virtual machine; return 0 if object is NULL
return handle == NULL ? 0 : ObjectSynchronizer::FastHashCode (THREAD,JNIHandles::resolve_non_null(handle)) ;
JVM_END
对于hashcode生成的逻辑由synchronizer.cpp的get_next_hash函数决定,实现比较复杂,根据hashcode的不同值有不同的生成策略,最后使用一个hash掩码处理。
static inline intptr_t get_next_hash(Thread * Self,oop obj) {
intptr_t value = 0 ;
if (hashCode == 0) {
value = os::random() ;
} else
if (hashCode == 1) {
intptr_t addrBits = intptr_t(obj) >> 3 ;
value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ;
} else
if (hashCode == 2) {
value = 1 ;
// for sensitivity testing
} else
if (hashCode == 3) {
value = ++GVars.hcSequence ;
} else
if (hashCode == 4) {
value = intptr_t(obj) ;
} else {
unsigned t = Self->_hashStateX ;
t ^= (t << 11) ;
Self->_hashStateX = Self->_hashStateY ;
Self->_hashStateY = Self->_hashStateZ ;
Self->_hashStateZ = Self->_hashStateW ;
unsigned v = Self->_hashStateW ;
v = (v ^ (v >> 19)) ^ (t ^ (t >> 8)) ;
Self->_hashStateW = v ;
value = v ;
}
value &= markOopDesc::hash_mask;
if (value == 0) value = 0xBAD ;
assert (value != markOopDesc::no_hash,"invariant") ;
TEVENT (hashCode: GENERATE) ;
return value;
}
equals方法 这是一个非本地方法,判断逻辑也十分简单,直接==比较。 clone方法 由本地方法表知道clone方法对应的本地函数为JVM_Clone,clone方法主要实现对象的克隆功能,根据该对象生成一个相同的新对象(我们常见的类的对象的属性如果是原始类型则会克隆值,但如果是对象则会克隆对象的地址)。Java的类要实现克隆则需要实现Cloneable接口,if (!klass->is_cloneable())这里会校验是否有实现该接口。然后判断是否是数组分两种情况分配内存空间,新对象为new_obj,接着对new_obj进行copy及C++层数据结构的设置。最后再转成jobject类型方便转成Java层的Object类型。
JVM_ENTRY(jobject,JVM_Clone(JNIEnv* env,jobject handle))
JVMWrapper("JVM_Clone");
Handle obj(THREAD,JNIHandles::resolve_non_null(handle));
const KlassHandle klass (THREAD,obj->klass());
JvmtiVMObjectAllocEventCollector oam;
if (!klass->is_cloneable()) {
ResourceMark rm(THREAD);
THROW_MSG_0(vmSymbols::java_lang_CloneNotSupportedException(),klass->external_name());
}
const int size = obj->size();
oop new_obj = NULL;
if (obj->is_javaArray()) {
const int length = ((arrayOop)obj())->length();
new_obj = CollectedHeap::array_allocate(klass,size,length,CHECK_NULL);
} else {
new_obj = CollectedHeap::obj_allocate(klass,CHECK_NULL);
}
Copy::conjoint_jlongs_atomic((jlong*)obj(),(jlong*)new_obj,(size_t)align_object_size(size) / HeapWordsPerlong);
new_obj->init_mark();
BarrierSet* bs = Universe::heap()->barrier_set();
assert(bs->has_write_region_opt(),"Barrier set does not have write_region");
bs->write_region(MemRegion((HeapWord*)new_obj,size));
if (klass->has_finalizer()) {
assert(obj->is_instance(),"should be instanceOop");
new_obj = instanceKlass::register_finalizer(instanceOop(new_obj),CHECK_NULL);
}
return JNIHandles::make_local(env,oop(new_obj));
JVM_END
toString方法 逻辑是获取class名称加上@再加上十六进制的hashCode。 notify方法 (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
