Java從JDK源碼角度對(duì)Object進(jìn)行實(shí)例分析
Object是所有類(lèi)的父類(lèi),也就是說(shuō)java中所有的類(lèi)都是直接或者間接繼承自O(shè)bject類(lèi)。比如你隨便創(chuàng)建一個(gè)classA,雖然沒(méi)有明說(shuō),但默認(rèn)是extendsObject的。
后面的三個(gè)點(diǎn)"..."表示可以接受若干不確定數(shù)量的參數(shù)。老的寫(xiě)法是Objectargs[]這樣,但新版本的java中推薦使用...來(lái)表示。例如
publicvoidgetSomething(String...strings)(){}
object是java中所有類(lèi)的父類(lèi),也就是說(shuō)所有的類(lèi),不管是自己創(chuàng)建的類(lèi)還是系統(tǒng)中的類(lèi)都繼承自object類(lèi),也就是說(shuō)所有的類(lèi)在任何場(chǎng)合都可以代替object類(lèi),根據(jù)里氏替換原則,子類(lèi)在任何場(chǎng)合都可以代替其父類(lèi),而父類(lèi)卻不一定能代替其子類(lèi),java中常說(shuō)的萬(wàn)物皆對(duì)象說(shuō)的其實(shí)就是這個(gè)道理!object類(lèi)體現(xiàn)了oop思想中的多態(tài),繼承,封裝,抽象四大特性!
object類(lèi)是所有類(lèi)的基類(lèi),不是數(shù)據(jù)類(lèi)型。這個(gè)你可以查詢(xún)jdk文檔了解,所有類(lèi)都繼承自O(shè)bject。
Object...objects這種參數(shù)定義是在不確定方法參數(shù)的情況下的一種多態(tài)表現(xiàn)形式。即這個(gè)方法可以傳遞多個(gè)參數(shù),這個(gè)參數(shù)的個(gè)數(shù)是不確定的。這樣你在方法體中需要相應(yīng)的做些處理。因?yàn)镺bject是基類(lèi),所以使用Object...objects這樣的參數(shù)形式,允許一切繼承自O(shè)bject的對(duì)象作為參數(shù)。這種方法在實(shí)際中應(yīng)該還是比較少用的。
Object[]obj這樣的形式,就是一個(gè)Object數(shù)組構(gòu)成的參數(shù)形式。說(shuō)明這個(gè)方法的參數(shù)是固定的,是一個(gè)Object數(shù)組,至于這個(gè)數(shù)組中存儲(chǔ)的元素,可以是繼承自O(shè)bject的所有類(lèi)的對(duì)象。
這些基礎(chǔ)東西建議你多看幾遍"Thinkinjava"
Java的Object是所有其他類(lèi)的父類(lèi),從繼承的層次來(lái)看它就是最頂層根,所以它也是唯一一個(gè)沒(méi)有父類(lèi)的類(lèi)。它包含了對(duì)象常用的一些方法,比如getClass、hashCode、equals、clone、toString、notify、wait等常用方法。所以其他類(lèi)繼承了Object后就可以不用重復(fù)實(shí)現(xiàn)這些方法。這些方法大多數(shù)是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類(lèi)時(shí)就會(huì)執(zhí)行該方法,對(duì)應(yīng)的本地方法為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]));
}
可以看到它間接調(diào)用了JNINativeInterface_結(jié)構(gòu)體的方法,簡(jiǎn)單可以看成是這樣:它干的事大概就是將Java層的方法名和本地函數(shù)對(duì)應(yīng)起來(lái),方便執(zhí)行引擎在執(zhí)行字節(jié)碼時(shí)根據(jù)這些對(duì)應(yīng)關(guān)系表來(lái)調(diào)用C/C++函數(shù),如下面,將這些方法進(jìn)行注冊(cè),執(zhí)行引擎執(zhí)行到hashCode方法時(shí)就可以通過(guò)關(guān)系表來(lái)查找到JVM的JVM_IHashCode函數(shù),其中()I還可以得知Java層上的類(lèi)型應(yīng)該轉(zhuǎn)為int類(lèi)型。這個(gè)映射其實(shí)就可以看成將字符串映射到函數(shù)指針。
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方法也是個(gè)本地方法,對(duì)應(yīng)的本地方法為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函數(shù)了,Java層的Class在C++層與之對(duì)應(yīng)的則是klassOop,所以關(guān)于類(lèi)的元數(shù)據(jù)和方法信息可以通過(guò)它獲得。
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方法將幾個(gè)本地方法注冊(cè)可知,hashCode方法對(duì)應(yīng)的函數(shù)為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
對(duì)于hashcode生成的邏輯由synchronizer.cpp的get_next_hash函數(shù)決定,實(shí)現(xiàn)比較復(fù)雜,根據(jù)hashcode的不同值有不同的生成策略,最后使用一個(gè)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方法
這是一個(gè)非本地方法,判斷邏輯也十分簡(jiǎn)單,直接==比較。
clone方法
由本地方法表知道clone方法對(duì)應(yīng)的本地函數(shù)為JVM_Clone,clone方法主要實(shí)現(xiàn)對(duì)象的克隆功能,根據(jù)該對(duì)象生成一個(gè)相同的新對(duì)象(我們常見(jiàn)的類(lèi)的對(duì)象的屬性如果是原始類(lèi)型則會(huì)克隆值,但如果是對(duì)象則會(huì)克隆對(duì)象的地址)。Java的類(lèi)要實(shí)現(xiàn)克隆則需要實(shí)現(xiàn)Cloneable接口,if (!klass->is_cloneable())這里會(huì)校驗(yàn)是否有實(shí)現(xiàn)該接口。然后判斷是否是數(shù)組分兩種情況分配內(nèi)存空間,新對(duì)象為new_obj,接著對(duì)new_obj進(jìn)行copy及C++層數(shù)據(jù)結(jié)構(gòu)的設(shè)置。最后再轉(zhuǎn)成jobject類(lèi)型方便轉(zhuǎn)成Java層的Object類(lèi)型。
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名稱(chēng)加上@再加上十六進(jìn)制的hashCode。
notify方法
此方法用來(lái)喚醒線(xiàn)程,final修飾說(shuō)明不可重寫(xiě)。與之對(duì)應(yīng)的本地方法為JVM_MonitorNotify,ObjectSynchronizer::notify最終會(huì)調(diào)用ObjectMonitor::notify(TRAPS),這個(gè)過(guò)程是ObjectSynchronizer會(huì)嘗試當(dāng)前線(xiàn)程獲取freeObjectMonitor對(duì)象,不成功則嘗試從全局中獲取。
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對(duì)象包含一個(gè)_WaitSet隊(duì)列對(duì)象,此對(duì)象保存著所有處于wait狀態(tài)的線(xiàn)程,用ObjectWaiter對(duì)象表示。notify要做的事是先獲取_WaitSet隊(duì)列鎖,再取出_WaitSet隊(duì)列中第一個(gè)ObjectWaiter對(duì)象,再根據(jù)不同策略處理該對(duì)象,比如把它加入到_EntryList隊(duì)列中。然后再釋放_(tái)WaitSet隊(duì)列鎖。它并沒(méi)有釋放synchronized對(duì)應(yīng)的鎖,所以鎖只能等到synchronized同步塊結(jié)束時(shí)才釋放。
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方法類(lèi)似,只是在取_WaitSet隊(duì)列時(shí)不是取第一個(gè)而是取所有。
wait方法
wait方法是讓線(xiàn)程等待,它對(duì)應(yīng)的本地方法是JVM_MonitorWait,間接調(diào)用了ObjectSynchronizer::wait,與notify對(duì)應(yīng),它也是對(duì)應(yīng)調(diào)用ObjectMonitor對(duì)象的wait方法。該方法較長(zhǎng),這里不貼出來(lái)了,大概就是創(chuàng)建一個(gè)ObjectWaiter對(duì)象,接著獲取_WaitSet隊(duì)列鎖將ObjectWaiter對(duì)象添加到該隊(duì)列中,再釋放隊(duì)列鎖。另外,它還會(huì)釋放synchronized對(duì)應(yīng)的鎖,所以鎖沒(méi)有等到synchronized同步塊結(jié)束時(shí)才釋放。
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方法
這個(gè)方法用于當(dāng)對(duì)象被回收時(shí)調(diào)用,這個(gè)由JVM支持,Object的finalize方法默認(rèn)是什么都沒(méi)有做,如果子類(lèi)需要在對(duì)象被回收時(shí)執(zhí)行一些邏輯處理,則可以重寫(xiě)finalize方法
總結(jié)
以上就是本文關(guān)于Java從JDK源碼角度對(duì)Object進(jìn)行實(shí)例分析的全部?jī)?nèi)容,希望對(duì)大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專(zhuān)題,如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!
相關(guān)文章
SpringBoot學(xué)習(xí)之Json數(shù)據(jù)交互的方法
這篇文章主要介紹了SpringBoot學(xué)習(xí)之Json數(shù)據(jù)交互的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-12-12
Mac配置 maven以及環(huán)境變量設(shè)置方式
這篇文章主要介紹了Mac配置 maven以及環(huán)境變量設(shè)置方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
Mybatis Trim標(biāo)簽用法簡(jiǎn)單介紹
這篇文章主要介紹了Mybatis Trim標(biāo)簽用法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-05-05
Mybatis-Plus自動(dòng)生成代碼的實(shí)現(xiàn)示例
在工作中,程序員很多時(shí)候都是在寫(xiě)類(lèi)似的代碼,可以使用自動(dòng)生成代碼,本文主要介紹了Mybatis-Plus自動(dòng)生成代碼的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下2023-11-11
使用Mybatis如何實(shí)現(xiàn)刪除多個(gè)數(shù)據(jù)
這篇文章主要介紹了使用Mybatis如何實(shí)現(xiàn)刪除多個(gè)數(shù)據(jù),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
SpringBoot+Hibernate實(shí)現(xiàn)自定義數(shù)據(jù)驗(yàn)證及異常處理
這篇文章主要為大家介紹了SpringBoot如何整合Hibernate自定義數(shù)據(jù)驗(yàn)證及多種方式異常處理,文中的示例代碼講解詳細(xì),感興趣的可以了解一下2022-04-04

