Object는 모든 클래스의 상위 클래스입니다. 즉, Java의 모든 클래스는 Object 클래스에서 직접 또는 간접적으로 상속됩니다. 예를 들어 A 클래스를 임의로 생성하는 경우 명시적으로 명시하지는 않았지만 기본적으로 Object를 확장합니다.
public void getSomething(String ... strings)(){}객체는 Java의 모든 클래스의 상위 클래스입니다. 즉, 직접 생성했든 시스템에서 생성했든 모든 클래스는 객체 클래스에서 상속됩니다. 즉, 모든 클래스는 언제든지 대체될 수 있습니다. Liskov 대체 원칙에 따르면 객체 클래스는 어떤 경우에도 상위 클래스를 대체할 수 있지만 상위 클래스가 반드시 하위 클래스를 대체할 수는 없습니다. 이는 실제로 Java에서 흔히 말하는 것입니다. 모든 것이 객체입니다! oop 사고의 다형성, 상속, 캡슐화, 추상화의 네 가지 주요 특성을 이해하세요!
객체 클래스는 데이터 유형이 아닌 모든 클래스의 기본 클래스입니다. 이에 대해 알아보려면 jdk 문서를 확인하세요.
Object ...objects 이러한 종류의 매개변수 정의는 메소드 매개변수가 불확실할 때의 다형성 표현의 한 형태입니다. 즉, 이 방법은 여러 매개변수를 전달할 수 있으며 매개변수 개수는 불확실합니다. 이런 방식으로 메서드 본문에서 그에 따라 일부 처리를 수행해야 합니다. Object가 기본 클래스이기 때문에 Object...objects 매개변수 형식을 사용하여 Object에서 상속된 모든 객체를 매개변수로 사용할 수 있습니다. 이 방법은 실제로는 상대적으로 거의 사용되지 않습니다.
Object[] obj는 Object 배열로 구성된 매개변수 형태입니다. 이 메소드의 매개변수는 고정되어 있으며 Object 배열입니다. 이 배열에 저장된 요소는 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方法被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方法也是个本地方法,对应的本地方法为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
由前面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; }
这是一个非本地方法,判断逻辑也十分简单,直接==比较。
由本地方法表知道clone方法对应的本地函数为JVM_Clone
,clone方法主要实现对象的克隆功能,根据该对象生成一个相同的新对象(我们常见的类的对象的属性如果是原始类型则会克隆值,但如果是对象则会克隆对象的地址)。Java的类要实现克隆则需要实现Cloneable接口,if (!klass->is_cloneable())
Java의 Object는 다른 모든 클래스의 상위 클래스이므로 상속 수준에서 최상위 루트이므로 유일한 클래스이기도 합니다. 부모 클래스가 없는 클래스. 여기에는 getClass
, hashCode
, equals
, clone
및 toString
, notify
, wait
및 기타 일반적인 방법. 따라서 다른 클래스는 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
registerNatives 메소드
🎜registerNatives 메소드는 정적 블록으로 수정되므로 Object 클래스가 로드될 때 이 메소드가 실행됩니다. 해당 로컬 메소드는Java_java_lang_Object_registerNatives입니다. code>를 보면 다음과 같이 🎜<pre class="brush:java;toolbar:false;">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</pre>🎜 <code>JNINativeInterface_
구조체의 메소드를 간접적으로 호출하는 것을 알 수 있습니다. 간단히 말해서 이렇게 보면 됩니다. 아마도 해당 메소드의 메소드 이름을 일치시키는 것일 겁니다. 실행 엔진을 용이하게 하는 로컬 함수가 있는 Java 레이어 바이트코드를 실행할 때 이러한 대응 테이블에 따라 C/C++ 함수가 호출되며, 실행 엔진이 hashCode
를 실행할 때 이러한 메소드가 등록됩니다. 메소드를 사용하면 JVM_IHashCode
함수를 통해 JVM을 찾을 수 있습니다. 여기서 ()I
는 Java 계층의 유형이 int로 변환되어야 함을 알 수도 있습니다. 유형. 이 매핑은 실제로 문자열을 함수 포인터에 매핑하는 것으로 볼 수 있습니다. 🎜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() ; } }🎜getClass 메서드🎜🎜getClass 메서드도 로컬 메서드입니다. 해당 로컬 메서드는 다음과 같이
Java_java_lang_Object_getClass
입니다. 🎜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🎜그래서 여기서는 주로
GetObjectClass
를 살펴보겠습니다. function, Java 해당 레이어의 Class는 C++ 레이어의 klassOop
에 해당하므로 이를 통해 해당 클래스에 대한 메타데이터 및 메소드 정보를 얻을 수 있다. 🎜rrreee🎜hashCode 메소드🎜🎜이전의 RegisterNatives 메소드에서 여러 로컬 메소드를 등록한 것을 볼 수 있듯이 hashCode 메소드에 해당하는 함수는 JVM_IHashCode
, 즉 🎜rrreee🎜해시코드가 생성하는 로직이다 synchronizer.cpp
의 get_next_hash
함수에 의해 생성되며 이는 더 복잡합니다. 해시코드의 다양한 값에 따라 다양한 생성 전략이 있으며 마지막으로 처리에는 해시 마스크가 사용됩니다. 🎜rrreee🎜equals method🎜🎜이것은 non-local 방식이며, 판단 논리도 매우 간단하고 직접적인 == 비교입니다. 🎜🎜clone 메소드🎜🎜로컬 메소드 표를 보면 clone 메소드에 해당하는 로컬 함수가 JVM_Clone
임을 알 수 있습니다. clone 메소드는 주로 객체의 복제 기능을 구현하고 동일한 새 객체를 생성합니다. 객체를 기반으로 합니다(공통 클래스 객체의 속성은 원시 유형인 경우 값을 복제하지만 객체인 경우 객체의 주소를 복제합니다). 복제를 구현하려면 Java 클래스에서 Cloneable 인터페이스를 구현해야 합니다. if (!klass->is_cloneable())
는 인터페이스가 구현되었는지 확인합니다. 그런 다음 배열인지 확인하고 두 가지 경우에 메모리 공간을 할당합니다. 새 객체는 new_obj이고, 그런 다음 new_obj의 C++ 레이어 데이터 구조를 복사하여 설정합니다. 마지막으로 Java 계층의 객체 유형으로의 변환을 용이하게 하기 위해 작업 객체 유형으로 변환됩니다. 🎜rrreee🎜toString 메소드🎜🎜 논리는 클래스 이름과 @, 16진수 해시 코드를 가져오는 것입니다. 🎜此方法用来唤醒线程,final修饰说明不可重写。与之对应的本地方法为JVM_MonitorNotify
,ObjectSynchronizer::notify
最终会调用ObjectMonitor::notify(TRAPS)
,这个过程是ObjectSynchronizer会尝试当前线程获取free ObjectMonitor对象,不成功则尝试从全局中获取。
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() ; } }
与notify方法类似,只是在取_WaitSet
队列时不是取第一个而是取所有。
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
这个方法用于当对象被回收时调用,这个由JVM支持,Object的finalize方法默认是什么都没有做,如果子类需要在对象被回收时执行一些逻辑处理,则可以重写finalize方法。
위 내용은 JDK 소스 코드 관점에서 본 객체의 Java 예제 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!