هل Java مضمونة لثوابت السلسلة المضمنة إذا كان من الممكن تحديدها في وقت الترجمة

StackOverflow https://stackoverflow.com/questions/1406616

  •  05-07-2019
  •  | 
  •  

سؤال

النظر في هذه الحالة:

public Class1 {
   public static final String ONE = "ABC";
   public static final String TWO = "DEF";
}

public Class2 {

  public void someMethod() {
    System.out.println(Class1.ONE + Class1.TWO);
  }
}

عادةً ما تتوقع أن يقوم المترجم بتضمين الثوابتين ONE وTWO.ولكن هل هذا السلوك مضمون؟هل يمكنك النشر في وقت التشغيل Class2 دون وجود Class1 في مسار الفصل، وتتوقع أن يعمل بغض النظر عن المترجمين، أم أن هذا تحسين اختياري للمترجم؟

يحرر:لماذا على الأرض تفعل هذا؟حسنًا، لدي ثابت يمكن مشاركته بين طرفي التطبيق (العميل والخادم عبر RMI) وسيكون من الملائم جدًا في هذه الحالة بالذات وضع الثابت على فئة يمكن أن تكون فقط على جانب واحد من تلك الفجوة ( لأنها من الناحية المنطقية هي التي تمتلك تلك القيمة الثابتة) بدلاً من وضعها في فئة ثوابت عشوائية لمجرد أنها تحتاج إلى مشاركتها من قبل كلا جانبي الكود.في وقت الترجمة، تكون جميعها مجموعة واحدة من الملفات المصدر، ولكن في وقت الإنشاء يتم تقسيمها حسب الحزمة.

هل كانت مفيدة؟

المحلول

من المؤكد أن يتم التعامل معها على أنها تعبير ثابت، ومن المؤكد أن يتم تدريبها القسم 15.28 من JLS:

التعبير الثابت لوقت الترجمة هو تعبير يدل على قيمة النوع البدائي أو سلسلة لا تكتمل فجأة وتتألف باستخدام ما يلي فقط:

  • حروف من النوع البدائي وأحرف من النوع String (§3.10.5)
  • يلقي على الأنواع البدائية ويلقي على كتابة السلسلة
  • العوامل الأحادية +، -، ~، و!(لكن ليس ++ أو --)
  • عوامل الضرب *، /، و٪
  • العوامل المضافة + و -
  • ...

...

ثوابت وقت الترجمة من سلسلة النوع "متدربة" دائمًا لتبادل مثيلات فريدة ، باستخدام String.Intern.

الآن، هذا لا يعني تمامًا أنه مضمون أن يتم تضمينه.ومع ذلك، يقول القسم 13.1 من المواصفات:

يتم حل الإشارات إلى الحقول التي هي متغيرات ثابتة (§4.12.4) في وقت الترجمة إلى القيمة الثابتة التي يتم الإشارة إليها.لا توجد إشارة إلى مثل هذا يجب أن يكون هناك حقل ثابت في التعليمات البرمجية في ملف ثنائي (باستثناء في الفئة أو الواجهة التي تحتوي على حقل ثابت ، والذي سيكون له رمز لتهيئته) ، وهذا ثابت يجب أن تظهر الحقول دائما على أنها كانت كذلك تهيئه;القيمة الأولية الافتراضية لنوع مثل هذا الحقل يجب لا يمكن ملاحظتها أبدا.

بعبارة أخرى، حتى لو لم يكن التعبير نفسه ثابتًا, ، فلا ينبغي أن يكون هناك أي إشارة إلى Class1.لذا نعم، أنت بخير.هذا لا بالضرورة أضمن استخدام القيمة المتسلسلة في الكود الثانوي، لكن البتات المشار إليها مسبقًا تضمن أن القيمة المتسلسلة مدمجة، لذلك سأكون كذلك بشكل كبير مندهش إذا لم يتم تضمين القيمة المتسلسلة فقط.وحتى لو لم يحدث ذلك، فأنت تضمن أنه سيعمل بدونه Class1.

نصائح أخرى

وتجميع أنه مع javac 1.6.0_14 تنتج بايت كود التالي:

public void someMethod();
  Code:
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc     #3; //String ABCDEF
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   return

وهكذا يتم متصلا السلاسل في وقت الترجمة ويتم تضمين النتيجة في تجمع ثابت CLASS2 ل.

ولن inlined من قبل المترجم ولكن من خلال مترجم في وقت التشغيل، وإذا أمكن تحويله إلى رمز التجميع.

لا يمكن أن تكون مضمونة، لأن ليس كل المترجمين (في JVM) تعمل بنفس الطريقة. ولكن أهم تطبيقات وسوف نفعل.

<الفرعية> للأسف ليس لدي رابط للحفاظ على هذا :(

أظن، لكن لا أعرف على وجه اليقين، أن هذا سينجح، لكنها لا تبدو فكرة جيدة.

الطرق "العادية" للقيام بذلك هي:

  1. ضع الثوابت في حزمة مشتركة بين العميل والخادم.من المفترض أن تكون هناك مثل هذه الحزمة، لأن هذا هو المكان الذي تذهب إليه الواجهات.
  2. إذا لم يكن هناك مثل هذه الحزمة، فقم بإنشاء فئتين بالثوابت المشتركة:واحد للخادم والآخر للعميل.

JLS 13.4.9 . في حين أنها لا تتطلب صراحة على أن الثوابت هي inlined من قبل المجمع، فإنه يلمح هذا التجميع ودعم الثوابت في تصريحات switch مشروط يسبب المترجم لدائما الثوابت المضمنة.

ويبدو أنك كنت الترميز نسختك الخاصة من القدرة صلب enum، والتي لا public static final بالنسبة لك، التسمية المناسبة عبر name() وtoString() (فضلا عن وجود بعض المزايا الأخرى، ولكن ربما وجود عيب من ذاكرة أكبر البصمة).

هل تستخدم نسخة قديمة من جاوة لا يتضمن التعداد حتى الآن؟

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top