عادةً ما تستخدم الكلمة الرئيسية أخيرًا في Java مع مجموعة Try Catch. تستخدم لأداء بعض عمليات إصدار الموارد قبل نهاية الطريقة أو عند حدوث استثناء. لقد شاهدت مؤخرًا بعض المقالات على الإنترنت تناقش ترتيب تنفيذ Try Catch في النهاية ، ويتم إعطاء أن الكتلة أخيرًا يتم تنفيذها في نهاية الطريقة.
هذه الآراء تعتقد عمومًا أن:
1) يتم تنفيذ الكلمة الرئيسية أخيرًا قبل العودة إلى الطريقة السابقة بعد بيان إرجاع البرنامج. سيتم حفظ قيمة الإرجاع في منطقة مؤقتة. بعد تنفيذ الكتلة النهائية ، سيتم إرجاع قيمة المنطقة المؤقتة.
2) إذا كانت هناك قيمة إرجاع في الكتلة الأخيرة ، فسيحل محل القيمة المخزنة في المنطقة المؤقتة للمحاولة السابقة أو كتلة التقاط في البرنامج.
ولكن هل المشكلة حقا مثل هذا؟ دعونا نفكر في الأمر بعناية. يشرح JVM وتنفيذ تعليمات Bytecode في وقت التشغيل. عندما ينفذ بيان العودة ، لا يعرف ما إذا كان هناك كتلة أخيرًا بعد ذلك؟ ماذا لو لم يكن هناك حظر أخيرًا؟ سواء كان ذلك تعليمة من رمز bytecode أو يجب أن تكون تعليمات الكمبيوتر واضحة. JVM ليس ذكيا. يجب أن تكون نفس التعليمات واضحة ولن تحتوي على معنيين. لذلك ، بغض النظر عن عبارة الإرجاع عند التشغيل ، سيتم ظهر محتوى المكدس وإعادته إلى طريقة الاتصال.
في الوقت نفسه ، يمكننا أن نرى أن كتاب "Deep in Java Virtual Machine" يعطي تفسيرًا آخر. عندما يقوم برنامج التحويل البرمجي Java بتجميع البند الأخير ، سيتم إنشاء تعليمات JSR. يتسبب في استدعاء JVM إلى روتين فرعي صغير للتنفيذ ، أي في الكتلة الأخيرة. في الوقت نفسه ، يتم تجميع عبارة Return 0 في البرنامج في متغير الإرجاع في المكدس إلى المتغير المحلي قبل استدعاء تعليمات JSR ، ويتم استدعاء تعليمات JSR ، ويتم تنفيذ الكتلة أخيرًا ، وإرجاع الكتلة أخيرًا. عندما يتم دفع قيمة الإرجاع في المتغير المحلي إلى المكدس ، يتم تنفيذ تعليمات IRETURN ، وتظهر قيمة الإرجاع من المكدس ، وتعود إلى طريقة الاتصال. هنا ، يتم حفظ قيمة الإرجاع في المتغير المحلي قبل تنفيذ تعليمات JSR ، لأنه قد يحدث استثناء أثناء تنفيذ الكتلة الأخيرة أو هناك أيضًا قيم إرجاع. وبهذه الطريقة فقط ، يمكن ضمان اتساق تنفيذ البرنامج النهائي. منذ أن تمت كتابة "تعميق الجهاز الافتراضي Java" لبعض الوقت ، يختلف تنفيذ ونسخة مترجم JVM الذي يستخدمه المؤلف أيضًا عن تلك التي تمت مناقشتها في هذه المقالة. لذلك بعد الاختبار ، هناك اختلاف طفيف في توليد Bytecodes لتطبيقات المترجمات المختلفة أو إصدارات المترجمين المختلفة لنفس البرنامج. إذا كنت مهتمًا ، فيمكنك إلقاء نظرة على رمز bytecode الذي تم إنشاؤه بواسطة البند الأخير في هذا الكتاب.
يتم تجميع جيل Bytecode في هذه المقالة وإنشائه بواسطة إصدار Oracle's JDK8U-25 من المترجم.
دعونا نلقي نظرة على مثال أدناه.
1. Catch Catch أخيرًا على سبيل المثال:
الفئة العامة أخيرًا {public static void main (string [] args) {int r = test () ؛ system.out.println (r) ؛ } int static public test () {try {system.out.println ("try") ؛ // العودة 1/0 ؛ العودة 0 ؛ } catch (استثناء e) {system.out.println ("استثناء") ؛ إرجاع 100 ؛ } أخيرًا {system.out.println ("أخيرًا") ؛ }}}استخدم عبارة الإرجاع 0 في كتلة المحاولة ، والنتيجة الجارية للبرنامج هي:
يحاول
أخيراً
0
استخدم عبارة الإرجاع 1/0 في كتلة المحاولة ، ونتيجة تشغيل البرنامج هي:
استثناء
أخيراً
100
في الواقع ، من خلال النتيجة الجارية ، يمكننا أن نرى أن الكتلة أخيرًا يتم تنفيذها بعد بيانات أخرى قبل بيان الإرجاع في مجموعة المحاولة أو التمسك. وبعبارة أخرى ، لا يتطابق ترتيب كتابة البرنامج الخاص بنا ، لأن JVM يفسر وينفذ رمز BYTECODE ، لذلك نحن بحاجة إلى معرفة كيف يجمع برنامج التحويل البرمجي Java هذا الرمز ومعرفة الشكل الذي تم إنشاؤه بواسطة رمز Bytecode.
2. جزء من رمز Bytecode الذي تم إنشاؤه بواسطة البرنامج: (يرجى الرجوع إلى تعليمات Java Bytecode)
اختبار int الثابت العام () ؛ واصف: () I Flags: ACC_Public ، ACC_STATAT CODE: Stack = 2 ، السكان المحليين = 2 ، args_size = 0 0: getStatic #20 // Field Java/lang/system.out: ljava/io/printstream ؛ 3: LDC #36 // String Try 5: InvokeVirtual #38 // الطريقة java/io/printstream.println: (ljava/lang/string ؛) v 8: getStatic #20 // Field Java/lang/system.out: ljava/io/printstream ؛ 11: 22: LDC #43 // String Exception 24: InvokeVirtual #38 // الطريقة java/io/printstream.println: (ljava/lang/string ؛) v 27: getStatic #20 // Field Java/lang/system.out: ljava/io/printstream ؛ 30: LDC #41 // String أخيرًا 32: InvokeVirtual #38 // الطريقة java/io/printstream.println: (ljava/lang/string ؛) v 35: bipush 100 37: iReturn 38: store_1 39: getStatic #20//field Java/lang. 42: LDC #41 // String أخيرًا 44: InvokeVirtual #38 // الطريقة java/io/printstream.println: (ljava/lang/string ؛) v 47: aload_1 48: Athrow استثناء جدول: من النوع الهدف 0 8 18 فئة Java/lang/استثناء 0 88 أي 2 27 27 38
من الجزء الأحمر ، يمكننا أن نرى أن الخطوط 10 و 11 تتوافق مع تعليمات بيان الأحكام أخيرًا ، تتوافق 16 و 17 مع تعليمات الإرجاع 0 ، بعد عبارات أخرى على كتلة المحاولة ، قبل العودة. 19 و 20 يتوافقان مع تعليمات الحظر أخيرًا ، 21 و 22 يتوافقان مع تعليمات الإرجاع 100. بعد التقاط بيانات أخرى وقبل العودة ، يمكننا أن نرى أن كل شيء يحدث وراء ذلك هو أن برنامج التحويل البرمجي Java قد فعل كل هذا بالنسبة لنا. بالنسبة للاستثناءات التي تحدث في البرنامج ، ستجد JVM موقع العنوان المقابل للتعامل مع استثناءات من جدول الاستثناءات للتنفيذ.
لذلك يمكننا أن نستنتج أن العبارات في الكتل أخيرًا سيتم إدراجها بواسطة برنامج التحويل البرمجي Java قبل كتلة Trylic و Catch Block Return ، وبعد البيانات الأخرى. لا توجد روتين فرعي لإنشاء مكالمات JSR هنا. لهذا السبب ، سواء كان ذلك تنفيذ كتلة المحاولة أو تنفيذ كتلة الصيد ، سيتم تنفيذ الكتلة أخيرًا قبل إرجاع الطريقة.
التحليل الشامل أعلاه لتوقيت تنفيذ Java أخيرًا هو كل المحتوى الذي أشاركه معك. آمل أن تتمكن من إعطائك مرجعًا وآمل أن تتمكن من دعم wulin.com أكثر.