Java-Beispielanalyse von Object aus der Perspektive des JDK-Quellcodes
Object ist die übergeordnete Klasse aller Klassen, was bedeutet, dass alle Klassen in Java direkt oder indirekt von der Object-Klasse erben. Wenn Sie beispielsweise beiläufig eine Klasse A erstellen, obwohl dies nicht explizit angegeben ist, wird standardmäßig „extends Object“ verwendet. Die drei Punkte „…“ nach
zeigen an, dass eine unbestimmte Anzahl von Parametern akzeptiert werden kann. Die alte Schreibweise ist Object args [], aber in der neuen Version von Java wird empfohlen, ... zu verwenden, um es auszudrücken. Beispielsweise ist
public void getSomething(String ... strings)(){}
object die übergeordnete Klasse aller Klassen in Java, was bedeutet, dass alle Klassen, unabhängig davon, ob sie von Ihnen selbst oder im System erstellt wurden, von der Objektklasse erben, also alle Klassen Die Objektklasse kann bei jeder Gelegenheit ersetzt werden. Nach dem Liskov-Substitutionsprinzip kann eine Unterklasse ihre übergeordnete Klasse jederzeit ersetzen, aber die übergeordnete Klasse ersetzt möglicherweise nicht unbedingt ihre Unterklasse. In Java wird oft gesagt, dass dies der Fall ist ein Objekt. Das ist die Wahrheit! Die Objektklasse verkörpert die vier Hauptmerkmale Polymorphismus, Vererbung, Kapselung und Abstraktion im Oop-Denken!
Die Objektklasse ist die Basisklasse aller Klassen, kein Datentyp. Weitere Informationen hierzu finden Sie in der JDK-Dokumentation. Alle Klassen erben von Object.
Objekt ...Objekte Diese Art der Parameterdefinition ist ein polymorpher Ausdruck, wenn die Methodenparameter unsicher sind. Das heißt, diese Methode kann mehrere Parameter übergeben und die Anzahl der Parameter ist ungewiss. Auf diese Weise müssen Sie im Methodenkörper eine entsprechende Verarbeitung durchführen. Da Object die Basisklasse ist, wird die Parameterform Object...objects verwendet, um die Verwendung aller von Object geerbten Objekte als Parameter zu ermöglichen. Diese Methode sollte in der Praxis relativ selten angewendet werden.
Object[] obj ist eine Parameterform, die aus einem Object-Array besteht. Beachten Sie, dass die Parameter dieser Methode fest sind und ein Object-Array sind. Die in diesem Array gespeicherten Elemente können Objekte aller Klassen sein, die von Object erben.
Es wird empfohlen, dass Sie für diese grundlegenden Dinge mehrmals „Think in Java“ lesen
Java-Objekt ist die übergeordnete Klasse aller anderen Klassen. Aus Sicht der Vererbung ist es die Wurzel der obersten Ebene Es handelt sich also auch um die einzige A-Klasse ohne übergeordnete Klasse. Es enthält einige häufig verwendete Methoden von Objekten, wie z. B. getClass
, hashCode
, equals
, clone
, toString
, notify
, wait
und andere gängige Methoden. Daher müssen andere Klassen diese Methoden nach dem Erben von Object nicht wiederholt implementieren. Bei den meisten dieser Methoden handelt es sich um native Methoden, die im Folgenden detailliert analysiert werden.
Der Hauptcode lautet wie folgt:
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-Methode
Da die registerNatives-Methode durch einen statischen Block geändert wird, wird diese Methode ausgeführt, wenn die Object-Klasse Die entsprechende lokale Methode ist Java_java_lang_Object_registerNatives
, wie unten gezeigt,
JNIEXPORT void JNICALL Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls) { (*env)->RegisterNatives(env, cls, methods, sizeof(methods)/sizeof(methods[0])); }
kann gesehen werden, dass sie indirekt die Methode der JNINativeInterface_
-Struktur aufruft Es kann einfach so gesehen werden. Was es bewirkt, ist wahrscheinlich die Konvertierung der entsprechenden Methodennamen in lokale Funktionen der Java-Schicht. Dies erleichtert der Ausführungs-Engine das Aufrufen von C/C++-Funktionen basierend auf diesen Korrespondenztabellen, wenn sie Bytecode ausführt. Wie unten gezeigt, können diese Methoden registriert werden, und die Ausführungs-Engine kann sie übergeben Beziehung beim Ausführen der hashCode
-Methode, um die JVM_IHashCode
-Funktion von JVM zu finden, wobei ()I
auch wissen kann, dass der Typ auf der Java-Ebene in den Typ int konvertiert werden soll. Diese Zuordnung kann tatsächlich als Zuordnung von Zeichenfolgen zu Funktionszeigern angesehen werden.
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-Methode
getClass-Methode ist auch eine lokale Methode, und die entsprechende lokale Methode ist Java_java_lang_Object_getClass
, wie folgt:
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); } }
Also die Hauptsache Was hier zu sehen ist, ist die GetObjectClass
-Funktion, die Klasse in der Java-Schicht entspricht klassOop
in der C++-Schicht, sodass Metadaten und Methodeninformationen über die Klasse über sie abgerufen werden können.
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-Methode
Aus der vorherigen registerNatives-Methode zum Registrieren mehrerer lokaler Methoden geht hervor, dass die der hashCode-Methode entsprechende Funktion JVM_IHashCode
ist, also
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
für Die Logik der Hashcode-Generierung wird durch die synchronizer.cpp
-Funktion von get_next_hash
bestimmt, und die Implementierung ist relativ kompliziert. Es gibt verschiedene Generierungsstrategien entsprechend unterschiedlichen Hashcode-Werten und schließlich einem Hash Für die Verarbeitung wird eine Maske verwendet.
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; }
Gleich-Methode
Dies ist eine nicht lokale Methode, und die Beurteilungslogik ist ebenfalls sehr einfach, direkter == Vergleich.
Klonmethode
Aus der lokalen Methodentabelle wissen wir, dass die der Klonmethode entsprechende lokale Funktion JVM_Clone
ist. Die Klonmethode implementiert hauptsächlich die Klonfunktion des Objekts und generiert eine Identisches neues Objekt basierend auf dem Objekt (wir Wenn die Eigenschaften gemeinsamer Klassenobjekte primitive Typen sind, wird der Wert geklont, wenn es sich jedoch um Objekte handelt, wird die Adresse des Objekts geklont). Um das Klonen zu implementieren, muss eine Java-Klasse die Cloneable-Schnittstelle implementieren. if (!klass->is_cloneable())
Hier wird überprüft, ob die Schnittstelle implementiert ist. Bestimmen Sie dann, ob es sich um ein Array handelt, und weisen Sie in zwei Fällen Speicherplatz zu. Das neue Objekt ist new_obj und kopiert und legt dann die C++-Schichtdatenstruktur von new_obj fest. Schließlich wird es in den Jobject-Typ konvertiert, um die Konvertierung in den Object-Typ der Java-Schicht zu erleichtern.
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-Methode
Die Logik besteht darin, den Klassennamen plus @ plus den hexadezimalen HashCode zu erhalten.
notify方法
此方法用来唤醒线程,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() ; } }
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方法。
Das obige ist der detaillierte Inhalt vonJava-Beispielanalyse von Object aus der Perspektive des JDK-Quellcodes. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

AI Hentai Generator
Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

Heiße Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen



Leitfaden zur perfekten Zahl in Java. Hier besprechen wir die Definition, Wie prüft man die perfekte Zahl in Java?, Beispiele mit Code-Implementierung.

Leitfaden zum Zufallszahlengenerator in Java. Hier besprechen wir Funktionen in Java anhand von Beispielen und zwei verschiedene Generatoren anhand ihrer Beispiele.

Leitfaden für Weka in Java. Hier besprechen wir die Einführung, die Verwendung von Weka Java, die Art der Plattform und die Vorteile anhand von Beispielen.

Leitfaden zur Smith-Zahl in Java. Hier besprechen wir die Definition: Wie überprüft man die Smith-Nummer in Java? Beispiel mit Code-Implementierung.

In diesem Artikel haben wir die am häufigsten gestellten Fragen zu Java Spring-Interviews mit ihren detaillierten Antworten zusammengestellt. Damit Sie das Interview knacken können.

Java 8 führt die Stream -API ein und bietet eine leistungsstarke und ausdrucksstarke Möglichkeit, Datensammlungen zu verarbeiten. Eine häufige Frage bei der Verwendung von Stream lautet jedoch: Wie kann man von einem Foreach -Betrieb brechen oder zurückkehren? Herkömmliche Schleifen ermöglichen eine frühzeitige Unterbrechung oder Rückkehr, aber die Stream's foreach -Methode unterstützt diese Methode nicht direkt. In diesem Artikel werden die Gründe erläutert und alternative Methoden zur Implementierung vorzeitiger Beendigung in Strahlverarbeitungssystemen erforscht. Weitere Lektüre: Java Stream API -Verbesserungen Stream foreach verstehen Die Foreach -Methode ist ein Terminalbetrieb, der einen Vorgang für jedes Element im Stream ausführt. Seine Designabsicht ist

Anleitung zum TimeStamp to Date in Java. Hier diskutieren wir auch die Einführung und wie man Zeitstempel in Java in ein Datum konvertiert, zusammen mit Beispielen.

Kapseln sind dreidimensionale geometrische Figuren, die aus einem Zylinder und einer Hemisphäre an beiden Enden bestehen. Das Volumen der Kapsel kann berechnet werden, indem das Volumen des Zylinders und das Volumen der Hemisphäre an beiden Enden hinzugefügt werden. In diesem Tutorial wird erörtert, wie das Volumen einer bestimmten Kapsel in Java mit verschiedenen Methoden berechnet wird. Kapselvolumenformel Die Formel für das Kapselvolumen lautet wie folgt: Kapselvolumen = zylindrisches Volumenvolumen Zwei Hemisphäre Volumen In, R: Der Radius der Hemisphäre. H: Die Höhe des Zylinders (ohne die Hemisphäre). Beispiel 1 eingeben Radius = 5 Einheiten Höhe = 10 Einheiten Ausgabe Volumen = 1570,8 Kubikeinheiten erklären Berechnen Sie das Volumen mithilfe der Formel: Volumen = π × R2 × H (4
