الكائن هو الفئة الأصل لجميع الفئات ، أي أن جميع الفئات في Java موروثة بشكل مباشر أو غير مباشر من فئة الكائن. على سبيل المثال ، إذا قمت بإنشاء classa ، على الرغم من أنها غير مذكورة بشكل صريح ، فهي الافتراضي للموسم.
تشير النقاط الثلاث التالية "..." إلى أنه يمكن قبول عدد غير مؤكد من المعلمات. الطريقة القديمة للكتابة هي ObjectArgs [] ، ولكن يوصى باستخدامها ... في الإصدار الجديد من Java. على سبيل المثال
publicvoidgetSomething(String...strings)(){}
الكائن هو الفئة الوالدية لجميع الفئات في جافا. وهذا يعني ، أن جميع الفئات ، سواء تم إنشاؤها بمفردها أو الفئات في النظام ، ورثت من فئة الكائن ، أي أن جميع الفئات يمكن أن تحل محل فئة الكائن في أي مناسبة. وفقًا لمبدأ استبدال ريتش ، يمكن أن تحل الفئات الفرعية محل فئة الوالدين في أي مناسبة ، ولكن قد لا تحل فئة الوالدين بالضرورة محل فئاتها الفرعية. ما يقال في كثير من الأحيان في جافا هو في الواقع هذه الحقيقة! تجسد فئة الكائن الخصائص الأربعة الرئيسية لأشكال تعدد الأشكال ، والميراث ، والتغليف ، والتجريد في فكرة OOP!
فئة الكائن هي الفئة الأساسية لجميع الفئات ، وليس نوع البيانات. يمكنك الاستعلام عن وثيقة JDK لفهم ذلك ، جميع الفئات موروثة من الكائن.
كائن ... الكائنات هذا تعريف المعلمة هو مظاهر متعددة الأشكال في حالة معلمات الطريقة غير المؤكدة. وهذا يعني أن هذه الطريقة يمكن أن تمرر معلمات متعددة ، وعدد هذه المعلمات غير مؤكد. وبهذه الطريقة ، تحتاج إلى القيام ببعض المعالجة المقابلة في الجسم. لأن الكائن عبارة عن فئة أساسية ، استخدم نموذج المعلمة مثل الكائن ... الكائنات ، مما يسمح لجميع الكائنات الموروثة من الكائن كمعلمات. يجب استخدام هذه الطريقة نادراً ما تكون في الممارسة العملية.
شكل كائن [] OBJ هو نموذج معلمة يتكون من صفيف كائن. هذا يعني أن معلمات هذه الطريقة ثابتة وهي صفيف كائن. أما بالنسبة للعناصر المخزنة في هذه الصفيف ، يمكن أن تكون كائنات موروثة من جميع فئات الكائن.
يوصى بقراءة هذه الأشياء الأساسية عدة مرات "Thinkinjava"
كائن Java هو الفئة الوالدية لجميع الفئات الأخرى. من منظور الميراث ، هو الجذر على المستوى الأعلى ، لذلك فهو أيضًا الفئة الوحيدة بدون فئة الوالدين. أنه يحتوي على بعض الطرق الشائعة الاستخدام للكائنات ، مثل getClass ، hashcode ، متساوية ، استنساخ ، tostring ، الإخطار ، الانتظار وغيرها من الطرق شائعة الاستخدام. لذلك ، بعد أن ترث فئات أخرى كائن ، يمكنهم تنفيذ هذه الأساليب دون تنفيذ متكرر. معظم هذه الطرق هي الطرق الأصلية ، ويتم إجراء التحليل التفصيلي التالي.
الرمز الرئيسي هو كما يلي:
كائن الفئة العامة {private static native void registernavers () ؛ static {registernaits () ؛} الفئة الأصلية النهائية العامة <؟> getClass () ؛ public native int hashcode () ؛ boolean public يساوي (Object obj) {return (this == obj) ؛ getClass (). alfulalArgumentException ("قيمة المهلة سلبية") ؛} if (nanos <0 || nanos> 999999) {رمي جديد alfulalArgumentException ( اللمسات النهائية void () رمي {}}طريقة التسجيل
نظرًا لأن طريقة التسجيلات يتم تعديلها بواسطة كتلة ثابتة ، سيتم تنفيذ الطريقة عند تحميل فئة الكائن. الطريقة المحلية المقابلة هي java_java_lang_object_registernosts ، على النحو التالي ،
jniexport void jnicalljava_java_lang_object_registernivers (jnienv *env ، jclass cls) {( *env)-> التسجيلات (env ، cls ، الأساليب ، sizeof (methods)/sizeof (methods [0]) ؛}يمكنك أن ترى أنه يدعو بشكل غير مباشر طريقة بنية jninistativeInterface_ ، والتي يمكن اعتبارها ببساطة: ما يفعله ربما يتوافق مع اسم طريقة طبقة Java مع الوظيفة المحلية ، بحيث يمكن لمحرك التنفيذ استدعاء وظائف C/C ++ استنادًا إلى جداول العلاقة المقابلة عند التنفيذ. كما هو موضح أدناه ، سجل هذه الأساليب. عندما يقوم محرك التنفيذ بتنفيذ طريقة HashCode ، يمكنه العثور على وظيفة JVM_IHASHCode من JVM من خلال جدول العلاقة. () يمكنني أيضًا أن أعرف أنه يجب تحويل الأنواع الموجودة على طبقة Java إلى نوع int. يمكن اعتبار هذا التعيين في الواقع رسم خرائط لسلسلة إلى مؤشر وظيفة.
أساليب jninativemethod ثابتة [] = {{"hashcode" ، "() i" ، (void *) & jvm_ihashcode} ، {"wait" ، "(j) v" ، (void *) & jvm_monitorwait} ، {" "() v" ، (void *) & jvm_monitornotifyall} ، {"clone" ، "() ljava/lang/object ؛" ، (void *) & jvm_clone} ،} ؛ طريقة getClass
طريقة getClass هي أيضًا طريقة محلية ، والطريقة المحلية المقابلة هي Java_java_lang_object_getclass ، على النحو التالي:
jniexport jclass jnicalljava_java_lang_object_getclass (jnienv *env ، joleject this) {if (this == null) {jnu_thrownullpointerxception (env ، null) ؛ العودة 0 ؛ } آخر {return (*env)-> getObjectClass (env ، this) ؛ }}لذلك هنا ننظر بشكل أساسي إلى وظيفة getObjectClass. الفئة المقابلة في طبقة Java في طبقة C ++ هي Klassoop ، لذلك يمكن الحصول على معلومات البيانات الوصفية والطريقة حول الفصل.
jni_entry (jclass ، jni_getObjectClass (jnienv *env ، Job OBJ)) jniwrapper ("getObjectClass") ؛ dtrace_probe2 (hotspot_jni ، getObjectClass__entry ، env ، obj) ؛ klassoop k = jnihandles :: solve_non_null (obj)-> klass () ؛ jClass Ret = (jClass) jnihandles :: make_local (env ، klass :: cast (k)-> java_mirror ()) ؛ dtrace_probe1 (hotspot_jni ، getObjectClass__ ، ret) ؛ إرجاع ret ؛ jni_endطريقة Hashcode
من طريقة التسجيلات السابقة يسجل العديد من الأساليب المحلية ، يمكننا أن نرى أن الوظيفة المقابلة لطريقة HashCode هي JVM_IHASHCODE ، وهذا هو ،
JVM_ENTRY (JINT ، JVM_IHASHCODE (JNIENV* ENV ، JOB -HANDGE)) JVMWRAPPER ("JVM_IHASHCODE") ؛ // كما تم تنفيذها في الجهاز الظاهري الكلاسيكي ؛ إرجاع 0 إذا كان الكائن هو مقبض إرجاع فارغ == NULL؟ 0.يتم تحديد المنطق الذي تم إنشاؤه لـ HashCode بواسطة وظيفة get_next_hash من synchronizer.cpp. التنفيذ معقد نسبيا. هناك استراتيجيات توليد مختلفة تستند إلى قيم مختلفة من رمز Hashcode ، وأخيراً يتم استخدام قناع التجزئة لمعالجته.
ثابتة intptr_t get_next_hash (مؤشر ترابط * self ، OOP OBJ) {intptr_t value = 0 ؛ if (hashCode == 0) {value = os :: random () ؛ gvars.stwrandom ؛} آخر if (hashcode == 2) {value = 1 ؛ // لاختبار الحساسية} آخر إذا (hashcode == 3) {value = ++ gvars.hcsepl << 11) ؛ self-> _ hashstatex = self-> _ hashstatey ؛ self-> _ hashStatey = self-> _ hashstatez ؛ self-> _ hashstatez = self-> _ hashstatew ؛ unsigned v = ؛ self-> _ hashStatew = v ؛ value = v ؛} value & = markoopdesc :: hash_mask ؛ if (value == 0) value = 0xbad ؛ تساوي الطريقة
هذه طريقة غير محلية ، ومنطق الحكم بسيطًا للغاية ، وهو مقارنة مباشرة ==.
طريقة استنساخ
من جدول الطريقة المحلية ، نعلم أن الوظيفة المحلية المقابلة لطريقة الاستنساخ هي JVM_Clone. تقوم طريقة Clone بشكل أساسي بتنفيذ وظيفة الاستنساخ للكائن وإنشاء نفس الكائن الجديد استنادًا إلى الكائن (ستعمل سمات كائن فئتنا المشتركة على استنساخ القيمة إذا كانت نوعًا بدائيًا ، ولكن إذا كان كائنًا ، فسيتم استنساخ عنوان الكائن). لتنفيذ استنساخ فصول Java ، تحتاج إلى تنفيذ الواجهة المستنسخة. إذا كان (! klass-> is_clonable ()) سيتحقق مما إذا كانت الواجهة قد تم تنفيذها. ثم حدد ما إذا كان يتم تخصيص مساحة الذاكرة في حالتين. الكائن الجديد هو new_obj ، ثم يتم ضبط بنية بيانات طبقة C ++ لـ New_OBJ. أخيرًا ، سيتم تحويله إلى نوع الوظيفة إلى نوع كائن طبقة Java.
jvm_entry (Jobject ، jvm_clone (jnienv* env ، مقبض الوظائف)) jvmwrapper ("jvm_clone") ؛ التعامل مع OBJ (thread ، jnihandles :: solve_non_null (handle) ؛ (! klass-> is_clonable ()) {resourcemark rm (thread) ؛ throw_msg_0 (vmsymbols :: java_lang_clonenotsupportededexception () ، klass-> external_name ()) ؛ int length = (((Arrayoop) obj ())-> length () ؛ new_obj = collectedHeap :: array_allocate (klass ، size ، engle ، check_null) ؛} else {new_obj = collectedheap :: obj_allocate (klass ، size ، check_null) ؛} copy: (jlong*) new_obj ، (size_t) align_object_size (size) / heapwordsperlong) ؛ new_obj-> init_mark () ؛ barrierset* bs = unitere :: heap ()-> barrier_set () ؛ write_region ") ؛ bs-> write_region (((heapword*) new_obj ، size)) ؛ if (klass-> has_finalizer ()) {assert (obj-> is_instance () ،" jnihandles :: make_local (env ، OOP (new_obj)) ؛ jvm_endطريقة tostring
المنطق هو الحصول على اسم الفصل بالإضافة إلى @ Plus Hexadecimal Hashcode.
أبلغ الطريقة
يتم استخدام هذه الطريقة لإيقاظ سلسلة الرسائل ، ولا يمكن إعادة كتابة تعليمات التعديل النهائي. الطريقة المحلية المقابلة هي jvm_monitornotify. ObjectSynchronizer :: إخطار سوف يستدعي في النهاية ObjectMonitor :: إخطار (مصائد). هذه العملية هي أن ObjectSynchronizer سيحاول الحصول على كائن FreeObjectMonitor في مؤشر الترابط الحالي ، ومحاولة الحصول عليه من العالم إذا فشلت.
jvm_entry (void ، jvm_monitornotify (jnienv* env ، job job)) jvmwrapper ("jvm_monitornotify") ؛ التعامل مع OBJ (Thread ، JniHandles :: solve_non_null (handle)) ؛ Assert (obj-> is_instance () || obj-> is_array () ، "jvm_monitornotify يجب أن ينطبق على كائن") ؛ ObjectSynchronizer :: إخطار (OBJ ، تحقق) ؛ JVM_ENDيحتوي كائن ObjectMonitor على كائن قائمة انتظار _waitset ، والذي يحتفظ بجميع مؤشرات الترابط في حالة الانتظار ويتم تمثيله بواسطة كائن ObjectWaiter. ما يجب أن يتم إخطاره هو الحصول أولاً على قفل قائمة انتظار _waitset ، ثم إزالة كائن ObjectWaiter الأول في قائمة انتظار _waitset ، ثم معالجة الكائن وفقًا لاستراتيجيات مختلفة ، مثل إضافته إلى قائمة انتظار _entrylist. ثم حرر قفل قائمة انتظار _waitset. لا يطلق القفل المقابل للمزامنة ، بحيث لا يمكن إطلاق القفل إلا حتى تنتهي كتلة المزامنة المتزامنة.
objectmonitor void :: إخطار (Traps) {check_owner () ؛ if (_waitset == null) {tevent (notify notify) ؛ return ؛} dtrace_monitor_probe (إعلام ، هذا ، object () = dequeuewaiter () ؛ if (iterator! = null) {tevent (etefer1-transfer) ؛ ضمان (iterator-> tstate == objectWaiter :: ts_wait ، "susteriant") ؛ ضمان (iterator-> _ إخطار == 0 ، " ؛} iterator-> _ إخطار = 1 ؛ objectwaiter * list = _entryList ؛ if (list! = null) {assert (list-> _ prev == null ، "invariant") ؛ assert (list-> tstate == objectwaiter :: ts_enter ، "isseriant") ؛ {// prepend to intradeListif (list == null) {iterator-> _ next = iterator-> _ prev = iterator ؛} else {list-> _ prev = iterator ؛ iterator-> _ next = list ؛ iterator-> _ prev = null ؛ _EntRylist ؛ null) {iterator-> _ next = iterator-> _ prev = null ؛ _entryList = iterator ؛} آخر {// النظر في: العثور على الذيل حاليًا يتطلب المشي الخطي // قائمة الإدخال. يمكننا أن نجعل الوصول إلى الذيل ثابتًا عن طريق تحويل // cdll بدلاً من استخدام dll.objectwaiter الحالي * tail ؛ for (tail = list ؛ tail-> _ next! = null ؛ tail = tail-> _ next) ؛ null ؛}} آخر إذا (policy == 2) {// prepend to cxq // prepend to cxqif (list == null) {iterator-> _ next = iterator-> _ prev = null ؛ _entrylist = iterator ؛} ell {iterator-> tState = objectwaiter: _cxq ؛ iterator-> _ next = front ؛ if (atomic :: cmpxchg_ptr (iterator ، & _cxq ، front) == front) {break ؛}}}}} آخر (policy ==) _cxq ؛ if (tail == null) {iterator-> _ next = null ؛ if (atomic :: cmpxchg_ptr (iterator ، & _cxq ، null) == null) {break ؛}} آخر {بينما tail-> _ next! = null) tail- ؛ iterator-> _ التالي = null ؛ break ؛}}} آخر {parkevent * ev = iterator-> _ event ؛ iterator-> tstate = objectwaiter :: ts_run ؛ orderaccess :: fence () ؛ ev-> unpark () ؛ يحمي قائمة انتظار الانتظار ، وليس قائمة الدخول. يمكننا // نقل عملية الإضافة إلى الدخول ، أعلاه ، خارج القسم الحرج // المحمي بواسطة _waitsetlock. في الممارسة العملية ، هذا ليس مفيدًا. باستخدام // استثناء مهلة Wait () ومقاطعة مالك الشاشة // هو الخيط الوحيد الذي يمسك _waitsetlock. لا يوجد أي محتوى تقريبًا // على _WaitSetSetLock ، لذا فليس من المربح تقليل طول القسم الحرج //طريقة الإخطار
على غرار طريقة الإخطار ، فهي فقط عند جلب قائمة انتظار _waitset ، فهي ليست الأولى بل كل شيء.
طريقة الانتظار
طريقة الانتظار تجعل الموضوع انتظر. الطريقة المحلية المقابلة لها هي JVM_MonitorWait ، والتي تستدعي بشكل غير مباشر ObjectSynchronizer :: Wait ، والتي تتوافق مع الإخطار. إنها أيضًا طريقة الانتظار المقابلة لاستدعاء كائن ObjectMonitor. هذه الطريقة طويلة ولن يتم نشرها هنا. ربما يكون إنشاء كائن ObjectWaiter ، ثم الحصول على قفل قائمة انتظار _waitset وإضافة كائن ObjectWaiter إلى قائمة الانتظار ، ثم حرر قفل قائمة الانتظار. بالإضافة إلى ذلك ، سيتم إطلاق القفل المقابل للمزامنة ، وبالتالي لا ينتظر القفل حتى تنتهي كتلة المزامنة المتزامنة.
jvm_entry (void ، jvm_monitorwait (jnienv* env ، job handle ، jlong ms)) jvmwrapper ("jvm_monitorwait") ؛ التعامل مع OBJ (Thread ، JniHandles :: solve_non_null (handle)) ؛ Assert (obj-> is_instance () || obj-> is_array () ، "jvm_monitorwait يجب أن ينطبق على كائن") ؛ JavathReadInObjectWaitState Jtiows (موضوع ، MS! = 0) ؛ if (jvmtiexport :: should_post_monitor_wait ()) {jvmtiexport :: post_monitor_wait ((javathread *) thread ، (OOP) obj () ، ms) ؛ } objectsynchronizer :: انتظر (OBJ ، MS ، Check) ؛ JVM_ENDالانتهاء من الطريقة
يتم استخدام هذه الطريقة لاستدعاء عند إعادة تدوير الكائن. هذا مدعوم من قبل JVM. طريقة الانتهاء من الكائن لا تفعل أي شيء افتراضيا. إذا احتاجت الفئة الفرعية إلى إجراء بعض المعالجة المنطقية عند إعادة تدوير الكائن ، فيمكن تجاوز طريقة الانتهاء.
لخص
ما سبق هو كل محتوى هذه المقالة حول تحليل مثال جافا للكائن من منظور رمز مصدر JDK. آمل أن يكون ذلك مفيدًا للجميع. يمكن للأصدقاء المهتمين الاستمرار في الرجوع إلى الموضوعات الأخرى ذات الصلة على هذا الموقع. إذا كانت هناك أي أوجه قصور ، فيرجى ترك رسالة لإشارةها. شكرا لك يا أصدقائك لدعمكم لهذا الموقع!