لماذا لا أساليب ثابتة في واجهات, ولكن حقول ثابتة و الطبقات الداخلية حسنا ؟ [قبل Java8] [مكررة]

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

  •  02-07-2019
  •  | 
  •  

سؤال

هذا السؤال سبق الجواب هنا:

كان هناك عدد قليل من الأسئلة هنا حول لماذا لا يمكنك أن تحدد أساليب ثابتة داخل واجهات, ولكن أيا منها معالجة التناقض الأساسي:لماذا يمكنك تحديد حقول ثابتة و الداخلية ثابتة أنواع داخل واجهة, ولكن ليس ثابت الأساليب ؟

الداخلية ثابتة أنواع ربما ليست مقارنة عادلة, منذ ذلك فقط النحوية السكر الذي يولد فئة جديدة ، ولكن لماذا المجالات ولكن ليس الأساليب ؟

حجة ضد أساليب ثابتة داخل واجهات هو أنه يكسر الجدول الظاهري القرار الاستراتيجية المستخدمة من قبل JVM ، لكن لا يجب أن تنطبق على حقول ثابتة ، أيالمترجم فقط مضمنة ؟

الاتساق هو ما أشتهي و جافا يجب أن يكون إما دعم لا السكون أي شكل من داخل واجهة ، أو يجب أن تكون متسقة والسماح لهم.

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

المحلول

وهو الرسمية الاقتراح تم السماح أساليب ثابتة في واجهات في جافا 7.هذا الاقتراح يجري تحت مشروع العملة.

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


تحديث: في جافا بوسي بودكاست #234, جو داركي ذكر الاقتراح بإيجاز قائلا "معقدة" و ربما لن تجعل في إطار مشروع العملة.


تحديث: في حين أنها لم يجعل في مشروع العملة لمدة 7 جافا Java 8 لا يدعم وظائف ثابتة في الواجهات.

نصائح أخرى

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

ثابت الحقول هناك (أ) لأنهم كانوا هناك في JDK 1.0 العديد من المراوغة القرارات في JDK 1.0 (ب) ثابت النهائي الحقول في واجهات أقرب ما يكون جافا كان الثوابت في ذلك الوقت.

ثابت الطبقات الداخلية في واجهات سمح لأن هذا محض النحوية السكر - الطبقة الداخلية ليست في الواقع أي شيء للقيام مع الفئة الأصل.

لذلك أساليب ثابتة لا يسمح ببساطة لأنه لا يوجد أي سبب مقنع أن تفعل ذلك ؛ الاتساق ليست مقنعة بما فيه الكفاية لتغيير الوضع الراهن.

بالطبع, هذا يمكن أن يكون مسموحا به في المستقبل JLS الإصدارات دون كسر أي شيء.

هناك ابدأ وأشر إلى إعلان أسلوب ثابت في واجهة.ولا يمكن تنفيذها من خلال مكالمة عادية MyInterface.staticMethod().(تحرير:منذ أن الجملة الأخيرة الخلط بين بعض الناس ، داعيا MyClass.staticMethod() ينفذ بدقة تنفيذ staticMethod على MyClass, والتي إذا MyClass هو واجهة لا يمكن أن توجد!) إذا كان يمكنك الاتصال بهم عن طريق تحديد تنفيذ الطبقة MyImplementor.staticMethod() ثم يجب أن تعرف الدرجة الفعلية ، لذلك لا يهم ما إذا كان يحتوي على واجهة ذلك أم لا.

والأهم من ذلك أساليب ثابتة أبدا تجاوزها ، إذا كنت تحاول أن تفعل:

MyInterface var = new MyImplementingClass();
var.staticMethod();

قواعد ثابتة أقول أن طريقة تعريف أعلن في نوع من فار يجب أن يتم تنفيذ.لأن هذا هو واجهة هذا مستحيل.

بالطبع يمكنك دائما إزالة ثابت الكلمة من طريقة.كل شيء سوف تعمل بشكل جيد.قد تضطر إلى قمع بعض التحذيرات إذا كان يطلق عليه من أسلوب مثيل.

للرد على بعض التعليقات أدناه, السبب كنت لا يمكن تنفيذه "النتيجة=MyInterface.staticMethod()" هو أنه سيكون لديك لتنفيذ نسخة من طريقة محددة في MyInterface.ولكن لا يمكن أن يكون هناك نسخة محددة في MyInterface لأنه واجهة.فإنه لا يجب رمز التعريف.

الغرض من واجهات هو تعريف العقد دون تقديم التنفيذ.ولذلك لا يمكن أن يكون أساليب ثابتة ، لأنه يجب أن يكون التنفيذ بالفعل في واجهة منذ كنت لا يمكن تجاوز أساليب ثابتة.كما أن الحقول الثابتة فقط final fields ويسمح التي هي أساسا الثوابت (في 1.5+ هل يمكن أن يكون أيضا enums في واجهات).الثوابت هناك للمساعدة في تحديد واجهة دون الأرقام السحرية.

راجع للشغل, ليس هناك حاجة لتحديد صراحة static final معدلات الحقول في الواجهات فقط لأن ثابت النهائي المجالات المسموح بها.

هذا هو الموضوع القديم , ولكن هذا شيء مهم جدا السؤال عن كل شيء.منذ لاحظت هذا اليوم فقط لذلك أنا أحاول أن أشرح ذلك في نظافة الطريق:

والغرض الرئيسي من واجهة هو تقديم ما هو unimplementable ، حتى إذا أنها توفر

أساليب ثابتة المسموح به

ثم يمكنك استدعاء هذا الأسلوب باستخدام interfaceName.staticMethodName(), لكن هذا لم تنفذ طريقة يحتوي على لا شيء.لذلك فمن العبث أن تسمح أساليب ثابتة.ولذلك فإنها لا توفر هذا على الإطلاق.

حقول ثابتة مسموح

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

الطبقات الداخلية يسمح

الطبقات الداخلية مسموح لأنه بعد تجميع مختلف ملف فئة من الطبقة الداخلية إنشاء يقول InterfaceName$InnerClassName.class أنت تقدم في كيان كل ذلك معا ولكن ليس في واجهة.لذا التنفيذ في الطبقات الداخلية يتم توفيرها.

آمل أن يكون هذا سوف يساعد.

في الواقع في بعض الأحيان هناك أسباب شخص يمكن أن تستفيد من أساليب ثابتة.أنها يمكن أن تستخدم أساليب المصنع للفئات التي تنفذ واجهة.على سبيل المثال هذا هو السبب لدينا مجموعة واجهة مجموعات الطبقة في openjdk الآن.لذلك هناك الحلول كما هو الحال دائما - تقديم فئة أخرى مع القطاع الخاص منشئ والتي سوف تكون بمثابة "مساحة" عن أساليب ثابتة.

قبل جافا 5 ، وهو شائع الاستخدام ثابت حقول:

interface HtmlConstants {
    static String OPEN = "<";
    static String SLASH_OPEN = "</";
    static String CLOSE = ">";
    static String SLASH_CLOSE = " />";
    static String HTML = "html";
    static String BODY = "body";
    ...
}

public class HtmlBuilder implements HtmlConstants { // implements ?!?
    public String buildHtml() {
       StringBuffer sb = new StringBuffer();
       sb.append(OPEN).append(HTML).append(CLOSE);
       sb.append(OPEN).append(BODY).append(CLOSE);
       ...
       sb.append(SLASH_OPEN).append(BODY).append(CLOSE);
       sb.append(SLASH_OPEN).append(HTML).append(CLOSE);
       return sb.toString();
    }
}

هذا يعني HtmlBuilder لن يكون مؤهلا بعضها ثابت ، لذلك يمكن استخدام فتح بدلا من HtmlConstants.فتح

استخدام الأدوات في هذه الطريقة هو في نهاية المطاف مربكة.

الآن مع جافا 5 ، لدينا استيراد ثابت بناء الجملة من أجل تحقيق نفس التأثير:

private final class HtmlConstants {
    ...
    private HtmlConstants() { /* empty */ }
}

import static HtmlConstants.*;
public class HtmlBuilder { // no longer uses implements
    ...
}

لا يوجد سبب حقيقي لعدم وجود أساليب ثابتة في واجهات إلا:لغة جافا المصممين لا تريد ذلك.من وجهة النظر الفنية ومن المنطقي أن تسمح لهم.بعد كل فئة مجردة يمكن أن يكون لهم كذلك.أفترض ولكن لم يتم اختبار هذا يمكنك "اليد الحرفية" رمز بايت حيث واجهة لديها أسلوب ثابت وينبغي أن imho العمل مع أية مشاكل على استدعاء الأسلوب و/أو استخدام واجهة عادة.

كثيرا ما كنت أتساءل لماذا أساليب ثابتة في كل شيء ؟ لديهم استخداماتها ، ولكن حزمة/مساحة على مستوى أساليب المحتمل أن تغطي 80 ما أساليب ثابتة تستخدم.

اثنين من الأسباب الرئيسية التي تتبادر إلى الذهن:

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

  2. واجهات أليس من المفترض أن يكون القانون ؛ هذا ما فئات مجردة هي.المغزى من واجهة هو لتمكنك من التحدث عن ربما لا علاقة لها الأشياء التي يحدث لها كل مجموعة معينة من الأساليب.في الواقع تقدم تنفيذ تلك الأساليب هو خارج حدود ما واجهات يقصد به أن يكون.

أساليب ثابتة ترتبط فئة.في جافا, واجهة ليس تقنيا من الدرجة ، بل هو نوع, ولكن ليس فئة (وبالتالي ، فإن الكلمة بتنفيذ واجهات لا تمتد كائن).لأن واجهات لا دروس لا يمكنهم أساليب ثابتة ، لأنه لا يوجد الفعلية الدرجة إرفاق.

يمكنك الاتصال InterfaceName.class للحصول على كائن الفئة المقابلة واجهة ، ولكن الطبقة الطبقة تحديدا الدول التي تمثل فئات و واجهات في تطبيق جافا.ومع ذلك ، فإن واجهة نفسه لا يعامل أحدا وبالتالي لا يمكنك إرفاق أسلوب ثابت.

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

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

والسبب هو أن جميع الطرق المحددة في واجهة هي مجردة أم لا تعلن صراحة أن معدل.مجردة أسلوب ثابت غير المسموح به مزيج من المعدلات منذ أساليب ثابتة لا يمكن تجاوزها.

لماذا واجهات تسمح حقول ثابتة.لدي شعور أنه ينبغي أن يعتبر "ميزة".الاحتمال الوحيد الذي يمكنني التفكير أن مجموعة ثوابت تطبيقات واجهة قد تكون مهتمة في.

أوافق على أن التناسق لن يكون أفضل نهج.لا ثابت أعضاء ينبغي أن يسمح في واجهة.

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

جافا 1.8 واجهة أسلوب ثابت مرئيا أساليب واجهة فقط, إذا كنا إزالة methodSta1 (طريقة) من InterfaceExample الصف ، ونحن لن تكون قادرة على استخدامها InterfaceExample الكائن.ومع ذلك مثل غيرها من أساليب ثابتة ، يمكننا استخدام واجهة أساليب ثابتة باستخدام اسم الفئة.على سبيل المثال, صالح بيان سوف يكون:exp1.methodSta1();

حتى بعد النظر أدناه على سبيل المثال يمكننا أن نقول :1) جافا واجهة أسلوب ثابت هو جزء من واجهة, نحن لا يمكن استخدامها لتنفيذ فئة الكائنات.

2) جافا واجهة ثابتة طرق جيدة عن توفير المرافق الطرق ، على سبيل المثال null الاختيار ، جمع وفرز سجل الخ.

3) جافا واجهة أسلوب ثابت يساعدنا في توفير الأمن من خلال عدم السماح تنفيذ الطبقات (InterfaceExample) لتجاوز لهم.

4) يمكننا تحديد واجهة أسلوب ثابت عن وجوه أساليب الفئة ونحن سوف تحصل على خطأ برنامج التحويل البرمجي كما "هذا أسلوب ثابت لا يمكن إخفاء سبيل المثال طريقة من وجوه".هذا هو لأنه لا يسمح في جاوة ، منذ كائن الفئة الأساسية لجميع فئات ونحن لا يمكن أن يكون واحد على مستوى الصف أسلوب ثابت وآخر سبيل المثال الطريقة مع نفس التوقيع.

5) يمكننا استخدام جافا واجهة أساليب ثابتة لإزالة دروس المرافق مثل مجموعات تتحرك في كل من أساليب ثابتة المقابلة واجهة ، سيكون من السهل العثور عليها واستخدامها.

public class InterfaceExample implements exp1 {

    @Override
    public void method() {
        System.out.println("From method()");
    }

    public static void main(String[] args) {
        new InterfaceExample().method2();
        InterfaceExample.methodSta2();      //  <---------------------------    would not compile
        // methodSta1();                        //  <---------------------------    would not compile
        exp1.methodSta1();
    }

    static void methodSta2() {          //          <-- it compile successfully but it can't be overridden in child classes
        System.out.println("========= InterfaceExample :: from methodSta2() ======");
    }
}


interface exp1 {

    void method();
    //protected void method1();         //          <--      error
    //private void method2();           //          <--      error
    //static void methodSta1();         //          <--      error it require body in java 1.8

    static void methodSta1() {          //          <-- it compile successfully but it can't be overridden in child classes
        System.out.println("========= exp1:: from methodSta1() ======");
    }

    static void methodSta2() {          //          <-- it compile successfully but it can't be overridden in child classes
        System.out.println("========= exp1:: from methodSta2() ======");
    }

    default void method2() { System.out.println("---  exp1:: from method2() ---");}
    //synchronized default void method3() { System.out.println("---");}             // <-- Illegal modifier for the interface method method3; only public, abstract, default, static 
                                                                                // and strictfp are permitted
    //final default void method3() { System.out.println("---");} //             <--      error
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top