欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java从JDK源码角度对Object进行实例分析

程序员文章站 2023-12-10 14:32:58
object是所有类的父类,也就是说java中所有的类都是直接或者间接继承自object类。比如你随便创建一个classa,虽然没有明说,但默认是extendsobject...

object是所有类的父类,也就是说java中所有的类都是直接或者间接继承自object类。比如你随便创建一个classa,虽然没有明说,但默认是extendsobject的。

后面的三个点"..."表示可以接受若干不确定数量的参数。老的写法是objectargs[]这样,但新版本的java中推荐使用...来表示。例如

publicvoidgetsomething(string...strings)(){}

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",  "()v",          (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, size, 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方法

此方法用来唤醒线程,final修饰说明不可重写。与之对应的本地方法为jvm_monitornotify,objectsynchronizer::notify最终会调用objectmonitor::notify(traps),这个过程是objectsynchronizer会尝试当前线程获取freeobjectmonitor对象,不成功则尝试从全局中获取。

jvm_entry(void, jvm_monitornotify(jnienv* env, jobject handle))
 jvmwrapper("jvm_monitornotify");
 handle obj(thread, jnihandles::resolve_non_null(handle));
 assert(obj->is_instance() || obj->is_array(), "jvm_monitornotify must apply to an object");
 objectsynchronizer::notify(obj, check);
jvm_end

objectmonitor对象包含一个_waitset队列对象,此对象保存着所有处于wait状态的线程,用objectwaiter对象表示。notify要做的事是先获取_waitset队列锁,再取出_waitset队列中第一个objectwaiter对象,再根据不同策略处理该对象,比如把它加入到_entrylist队列中。然后再释放_waitset队列锁。它并没有释放synchronized对应的锁,所以锁只能等到synchronized同步块结束时才释放。

void objectmonitor::notify(traps) {
	check_owner();
	if (_waitset == null) {
		tevent (empty-notify) ;
		return ;
	}
	dtrace_monitor_probe(notify, this, object(), thread);
	int policy = knob_movenotifyee ;
	thread::spinacquire (&_waitsetlock, "waitset - notify") ;
	objectwaiter * iterator = dequeuewaiter() ;
	if (iterator != null) {
		tevent (notify1 - transfer) ;
		guarantee (iterator->tstate == objectwaiter::ts_wait, "invariant") ;
		guarantee (iterator->_notified == 0, "invariant") ;
		if (policy != 4) {
			iterator->tstate = objectwaiter::ts_enter ;
		}
		iterator->_notified = 1 ;
		objectwaiter * list = _entrylist ;
		if (list != null) {
			assert (list->_prev == null, "invariant") ;
			assert (list->tstate == objectwaiter::ts_enter, "invariant") ;
			assert (list != iterator, "invariant") ;
		}
		if (policy == 0) {
			// prepend to entrylist
			if (list == null) {
				iterator->_next = iterator->_prev = null ;
				_entrylist = iterator ;
			} else {
				list->_prev = iterator ;
				iterator->_next = list ;
				iterator->_prev = null ;
				_entrylist = iterator ;
			}
		} else
		   if (policy == 1) {
			// append to entrylist
			if (list == null) {
				iterator->_next = iterator->_prev = null ;
				_entrylist = iterator ;
			} else {
				// consider: finding the tail currently requires a linear-time walk of
				// the entrylist. we can make tail access constant-time by converting to
				// a cdll instead of using our current dll.
				objectwaiter * tail ;
				for (tail = list ; tail->_next != null ; tail = tail->_next) ;
				assert (tail != null && tail->_next == null, "invariant") ;
				tail->_next = iterator ;
				iterator->_prev = tail ;
				iterator->_next = null ;
			}
		} else
		   if (policy == 2) {
			// prepend to cxq
			// prepend to cxq
			if (list == null) {
				iterator->_next = iterator->_prev = null ;
				_entrylist = iterator ;
			} else {
				iterator->tstate = objectwaiter::ts_cxq ;
				for (;;) {
					objectwaiter * front = _cxq ;
					iterator->_next = front ;
					if (atomic::cmpxchg_ptr (iterator, &_cxq, front) == front) {
						break ;
					}
				}
			}
		} else
		   if (policy == 3) {
			// append to cxq
			iterator->tstate = objectwaiter::ts_cxq ;
			for (;;) {
				objectwaiter * tail ;
				tail = _cxq ;
				if (tail == null) {
					iterator->_next = null ;
					if (atomic::cmpxchg_ptr (iterator, &_cxq, null) == null) {
						break ;
					}
				} else {
					while (tail->_next != null) tail = tail->_next ;
					tail->_next = iterator ;
					iterator->_prev = tail ;
					iterator->_next = null ;
					break ;
				}
			}
		} else {
			parkevent * ev = iterator->_event ;
			iterator->tstate = objectwaiter::ts_run ;
			orderaccess::fence() ;
			ev->unpark() ;
		}
		if (policy < 4) {
			iterator->wait_reenter_begin(this);
		}
		// _waitsetlock protects the wait queue, not the entrylist. we could
		// move the add-to-entrylist operation, above, outside the critical section
		// protected by _waitsetlock. in practice that's not useful. with the
		// exception of wait() timeouts and interrupts the monitor owner
		// is the only thread that grabs _waitsetlock. there's almost no contention
		// on _waitsetlock so it's not profitable to reduce the length of the
		// critical section.
	}
	thread::spinrelease (&_waitsetlock) ;
	if (iterator != null && objectmonitor::_sync_notifications != null) {
		objectmonitor::_sync_notifications->inc() ;
	}
}

notifyall方法

与notify方法类似,只是在取_waitset队列时不是取第一个而是取所有。

wait方法

wait方法是让线程等待,它对应的本地方法是jvm_monitorwait,间接调用了objectsynchronizer::wait,与notify对应,它也是对应调用objectmonitor对象的wait方法。该方法较长,这里不贴出来了,大概就是创建一个objectwaiter对象,接着获取_waitset队列锁将objectwaiter对象添加到该队列中,再释放队列锁。另外,它还会释放synchronized对应的锁,所以锁没有等到synchronized同步块结束时才释放。

jvm_entry(void, jvm_monitorwait(jnienv* env, jobject handle, jlong ms))
 jvmwrapper("jvm_monitorwait");
 handle obj(thread, jnihandles::resolve_non_null(handle));
 assert(obj->is_instance() || obj->is_array(), "jvm_monitorwait must apply to an object");
 javathreadinobjectwaitstate jtiows(thread, ms != 0);
 if (jvmtiexport::should_post_monitor_wait()) {
  jvmtiexport::post_monitor_wait((javathread *)thread, (oop)obj(), ms);
 }
 objectsynchronizer::wait(obj, ms, check);
jvm_end

finalize方法

这个方法用于当对象被回收时调用,这个由jvm支持,object的finalize方法默认是什么都没有做,如果子类需要在对象被回收时执行一些逻辑处理,则可以重写finalize方法

总结

以上就是本文关于java从jdk源码角度对object进行实例分析的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!