كيف يمكن الوصول إلى متغير ثابت قبل الإعلان؟
-
02-10-2019 - |
سؤال
public class Main {
static int x = Main.y;
// static int x = y; //Not allowed; y is not defined
static int y = x;
public static void main(String[] args) {
System.out.println(x);//prints 0
}
}
كيف يُسمح لي باستخدام y الحوض ، ولكن ليس مباشرة؟
متى يتم تعريف y؟
المحلول
يتم وصف القواعد الدقيقة التي تحكم الإشارة إلى الأمام إلى متغيرات الفصل في القسم §8.3.2.3 من JLS:
8.3.2.3 قيود على استخدام الحقول أثناء التهيئة
يحتاج إعلان العضو إلى الظهور بشكل نصي قبل استخدامه فقط إذا كان العضو مثيلًا (على التوالي
static
) حقل فئة أو واجهة C وجميع الشروط التالية عقد:
- يحدث الاستخدام في حالة (على التوالي
static
) التهيئة المتغيرة لـ C أو في حالة (على التواليstatic
) مُهيئة C.- الاستخدام ليس على الجانب الأيسر من المهمة.
- الاستخدام هو عبر اسم بسيط.
- C هو فئة أو واجهة الأعمق التي تحيط الاستخدام.
يحدث خطأ في وقت الترجمة إذا لم يتم تلبية أي من المتطلبات الأربعة أعلاه.
هذا يعني أن خطأ وقت الترجمة من برنامج الاختبار:
class Test { int i = j; // compile-time error: incorrect forward reference int j = 1; }
في حين أن المثال التالي يجمع بدون خطأ:
class Test { Test() { k = 2; } int j = 1; int i = j; int k; }
على الرغم من أن المنشئ (§8.8) للاختبار يشير إلى الحقل k الذي تم الإعلان عنه ثلاثة أسطر في وقت لاحق.
تم تصميم هذه القيود لالتقاط التهيئة الدائرية أو المشوهة في الترجمة أو المشوهة. وهكذا ، كلاهما:
class Z { static int i = j + 2; static int j = 4; }
و:
class Z { static { i = j + 2; } static int i, j; static { j = 4; } }
يؤدي إلى أخطاء وقت الترجمة. لا يتم فحص الوصول بالطرق بهذه الطريقة ، لذلك:
class Z { static int peek() { return j; } static int i = peek(); static int j = 1; } class Test { public static void main(String[] args) { System.out.println(Z.i); } }
ينتج الإخراج:
0
نظرًا لأن التهيئة المتغيرة لـ I يستخدم طريقة الفئة نظرة خاطفة للوصول إلى قيمة المتغير J قبل تهيئة J بواسطة مُعمى متغير ، وفي هذه النقطة لا يزال لديه قيمته الافتراضية (§4.12.5).
نصائح أخرى
أفترض أنه من خلال استخدام الفصل ، فإن المترجم سيؤجل البحث عن المتغير حتى يكتمل الفصل ، لذلك يجد y ، ولكن إذا حددته مثل التعليق ، فهو لم يتم تعريفه بعد حتى يفشل
يتم تعريف المتغيرات الثابتة بترتيب الإعلان في الفصل ، أثناء تحميل الفصل. عندما تقوم JVM بتحميل Main
صف دراسي، x
سيتم تعريفها ، ثم y
. لهذا السبب لا يمكنك استخدامه مباشرة y
عند التهيئة x
, ، يمكنك إنشاء شيء يسمى مرجع إلى الأمام, ، تشير إلى متغير غير محدد حاليًا ، وهذا غير قانوني للمترجم.
عند استخدام Main.y
, ، أعتقد أن ما يلي يحدث:
- أنت تحميل
Main
,x
تسمى التهيئة - عندما تحدد
x
أن تكون متساوية لMain.y
, ، يرى المترجم إشارة إلى فئة ، لذلك سينتهي بالتعريفx
إلى القيمة الحالية للعضوy
الطبقةMain
. يعامل هذه الحالة كما لوMain
كان فئة مختلفة.
لاحظ أنه في هذه الحالة ، عند التهيئة x
, y
لم يتم تعريفه في الوقت الحالي. لذا x
سيكون لها قيمة 0
.
لا يُسمح لك بالقيام بذلك لأنه لا معنى له. التفسير الوحيد الممكن هو ذلك ذ تتم تهيئته إلى الصفر ، ولديك بالفعل طريقتان لقول ذلك. أنت لست بحاجة إلى هذا.
ربما يقوم المترجم بإنشاء مراجع المتغيرات الثابتة مع القيم الافتراضية مع الفئة في المكدس ، عند إنشاءه ثم يعين القيم المقدمة.