لماذا تحظر جافا الحقول الثابتة في الطبقات الداخلية؟

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

سؤال

class OuterClass {
 class InnerClass {
  static int i = 100; // compile error
  static void f() { } // compile error
 }
} 

على الرغم من أنه لا يمكن الوصول إلى الحقل الثابت مع OuterClass.InnerClass.i, ، إذا أردت تسجيل شيء يجب أن يكون ثابتًا ، على سبيل المثال ، عدد الكائنات الداخلية التي تم إنشاؤها ، فسيكون من المفيد جعل هذا الحقل ثابتًا. لذا لماذا هل تحظر جافا الحقول/الأساليب الثابتة في الفصول الداخلية؟

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

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

المحلول

الفكرة وراء الفصول الداخلية هي العمل في سياق المثيل المرفق. بطريقة ما ، السماح للمتغيرات والأساليب الثابتة يتناقض مع هذا الدافع؟

8.1.2 الفصول الداخلية والحالات المرفقة

الطبقة الداخلية هي فئة متداخلة لا يتم إعلانها بشكل صريح أو ضمني. قد لا تعلن الفئات الداخلية المهيمنة الثابتة (الفقرة 8.7) أو واجهات الأعضاء. قد لا تعلن الفصول الداخلية عن الأعضاء الثابتة ، ما لم يتم تجميع الحقول الثابتة للوقت (الفقرة 15.28).

نصائح أخرى

ما أريد معرفته هو السبب في أن جافا تحظر الحقول/الأساليب الثابتة داخل الفصول الداخلية

لأن تلك الفئات الداخلية هي "مثيل" فصول داخلية. أي أنها مثل سمة مثيل للكائن المرفق.

نظرًا لأن فئات "مثيل" ، فليس من المنطقي السماح static الميزات ، ل static من المفترض أن تعمل بدون مثال في المقام الأول.

يبدو الأمر كما لو كنت تحاول إنشاء سمة ثابتة/مثيل في نفس الوقت.

خذ المثال التالي:

class Employee {
    public String name;
}

إذا قمت بإنشاء حالتين للموظف:

Employee a = new Employee(); 
a.name = "Oscar";

Employee b = new Employee();
b.name = "jcyang";

من الواضح لماذا لكل واحد قيمته الخاصة للعقار name, ، حق؟

يحدث الشيء نفسه مع الطبقة الداخلية ؛ كل مثيل من الفئة الداخلية مستقلة عن مثيل الفئة الداخلية الأخرى.

لذلك إذا حاولت إنشاء ملف counter سمة الفصل ، لا توجد طريقة لمشاركة هذه القيمة عبر حالتين مختلفتين.

class Employee {
    public String name;
    class InnerData {
        static count; // ??? count of which ? a or b? 
     }
}

عند إنشاء المثيل a و b في المثال أعلاه ، ما قد يكون قيمة صحيحة للمتغير الثابت count؟ لا يمكن تحديد ذلك ، لأن وجود InnerData الفئة تعتمد تماما على كل من الكائنات المرفقة.

لهذا السبب ، عندما يتم الإعلان عن الفصل static, ، لم يعد بحاجة إلى مثيل حي ، أن تعيش نفسه. الآن بعد عدم وجود تبعية ، يمكنك إعلان سمة ثابتة بحرية.

أعتقد أن هذا يبدو متكررًا ، لكن إذا فكرت في الاختلافات بين سمات الحالة مقابل الصفات ، فسيكون ذلك منطقيًا.

InnerClass لا تستطيع اخذه static الأعضاء لأنه ينتمي إلى مثيل (من OuterClass). إذا أعلنت InnerClass مثل static لفصله عن المثيل ، سيتم تجميع الكود الخاص بك.

class OuterClass {
    static class InnerClass {
        static int i = 100; // no compile error
        static void f() { } // no compile error
    }
}

راجع للشغل: ستظل قادرًا على إنشاء مثيلات InnerClass. static في هذا السياق يسمح بحدوث ذلك بدون مثيل محاط من OuterClass.

في الواقع ، يمكنك إعلان الحقول الثابتة إذا كانت ثوابت وكتبت في وقت الترجمة.

class OuterClass {
    void foo() {
        class Inner{
            static final int a = 5; // fine
            static final String s = "hello"; // fine
            static final Object o = new Object(); // compile error, because cannot be written during compilation
        }
    }
}

فيما يلي الدافع الذي أجده أفضل مناسبة لهذا "الحد": يمكنك تنفيذ سلوك حقل ثابت لفئة داخلية كحقل مثيل للكائن الخارجي ؛وانت ايضا لا أحتاج الحقول/الأساليب الثابتة. السلوك الذي أعنيه هو أن جميع مثيلات الفئة الداخلية لبعض الكائنات تشترك في حقل (أو طريقة).

لذا ، لنفترض أنك تريد حساب جميع مثيلات الفصل الداخلية ، ستفعل:

public class Outer{
    int nofInner; //this will count the inner class 
                  //instances of this (Outer)object
                  //(you know, they "belong" to an object)
    static int totalNofInner; //this will count all 
                              //inner class instances of all Outer objects
    class Inner {
        public Inner(){
            nofInner++;
            totalNofInner++;
        }
    }
}
  1. تسلسل تهيئة الفصل هو سبب حاسم.

نظرًا لأن الفئات الداخلية تعتمد على مثيل الفئة المرفقة/الخارجية ، لذلك يجب تهيئة الفئة الخارجية قبل تهيئة الفئة الداخلية.
هذا هو JLS يقول حول تهيئة الفصل. النقطة التي نحتاجها هي ، سيتم تهيئة الفئة T إذا

  • يتم استخدام حقل ثابت معلنته T والحقل ليس متغيرًا ثابتًا.

لذلك إذا كان لدى الفئة الداخلية الوصول الثابت للوصول إلى تهيئة تهيئة الفئة الداخلية ، ولكن هذا لن يضمن تهيئة الفئة المرفقة.

  1. سوف ينتهك بعض القواعد الأساسية. يمكنك الانتقال إلى القسم الأخير (إلى two cases) لتجنب أشياء noob

شيء واحد عنه static nested class, ، عندما بعض nested class هو static سوف يتصرف تمامًا مثل الطبقة العادية بكل الطرق ويرتبط بالفئة الخارجية.

لكن مفهوم Inner class/ non-static nested class هل سوف يرتبط مع instance من الفئة الخارجية/المرفقة. يرجى ملاحظة أنه مرتبط بـ نموذج ليس الفصل. يعني الارتباط الآن مع الحالة بوضوح ذلك (من مفهوم متغير المثيل) سيكون موجودًا داخل مثيل وسيكون مختلفًا بين الحالات.

الآن ، عندما نصنع شيئًا ثابتًا ، نتوقع أن يتم تهيئته عند تحميل الفصل ويجب مشاركته بين جميع الحالات. ولكن لكونك غير منتظمة ، حتى الطبقات الداخلية نفسها (يمكنك بالتأكيد نسيان مثيل الفصل الداخلي الآنلا تتم مشاركتها مع كل مثيل الفئة الخارجية/المرفقة (على الأقل من الناحية المفاهيمية) ، إذن كيف نتوقع أن يتم مشاركة بعض متغيرات الفئة الداخلية بين جميع مثيل الفئة الداخلية.

لذلك إذا سمحت لنا Java باستخدام متغير ثابت داخل فئة متداخلة غير ثابتة. سيكون هنالك حالتان.

  • إذا تمت مشاركته مع كل مثيل الطبقة الداخلية ، فسوف ينتهك مفهوم context of instance(المتغيرات الخاصة). إنه لا بعد ذلك.
  • إذا لم تتم مشاركته مع كل الأمثلة ، فسوف ينتهك مفهوم كونه ثابتًا. مرة أخرى لا.

بالكلمات البسيطة ، تكون الفئات الداخلية غير المستقلة متغيرًا للمثيل للفئة الخارجية ، ويتم إنشاؤها فقط عند إنشاء فئة خارجية ويتم إنشاء كائن فئة خارجي في وقت التشغيل أثناء إنشاء المتغيرات الثابتة في وقت تحميل الفصل. لذا فإن الطبقة الداخلية غير الستراتية هي شيء في وقت التشغيل وهذا هو السبب في أن ثابتًا ليس جزءًا من الطبقة الداخلية غير القتالية.

ملاحظة: تعامل مع الفئات الداخلية دائمًا مثل متغير لفئة خارجية ، فقد تكون ثابتة أو غير قاسية مثل أي متغيرات أخرى.

أعتقد أنه من أجل الاتساق. على الرغم من أنه لا يبدو أن هناك أي قيود تقنية على ذلك ، إلا أنك لن تكون قادرًا على الوصول إلى أعضاء ثابتين في الفصل الداخلي من الخارج ، أي OuterClass.InnerClass.i لأن الخطوة الوسطى ليست ثابتة.

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