سؤال

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

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

باستخدام كائنات مجهولة:

void doSomething() {
    for (/* Assume some loop */) {
        final Object obj1, obj2; // some free variables

        IWorker anonymousWorker = new IWorker() {
            doWork() {
                // do things that refer to obj1 and obj2
            }
        };
    }
}

تحديد الفصل أولاً:

void doSomething() {
    for (/* Assume some loop */) {
        Object obj1, obj2;
        IWorker worker = new Worker(obj1, obj2);
    }
}

static class Worker implements IWorker {
    private Object obj1, obj2;
    public CustomObject(Object obj1, Object obj2) {/* blah blah */}

    @Override
    public void doWork() {}
};
هل كانت مفيدة؟

المحلول

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

لن يظهر هذا في الأداء ، ولكنه سيؤثر عليك إذا قمت بتسلسل هذه الفصول.

نصائح أخرى

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

IMO ، يجب أن تركز على كتابة التعليمات البرمجية التي يمكن قراءتها ويمكن صيانتها ، وتجاهل مشكلات الأداء "الصغيرة" حتى يكون لديك صافي دليل على أنها مهمة ... استنادًا إلى تحديد التطبيق للتطبيق.

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

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

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

لقد لاحظت في الواقع الحصول على أهمية أداء عند إنشاء العديد من حالات فئة مجهولة.

التفكير إذا كان قد يكون بسبب الطبقة المحلية ثابتة ، لقد أزلت ذلك ولم يحدث فرقًا.

في حالتي ، كنت أفعل شيئًا 1000 اختيار 3 مرات وهو 499500. استغرق الإصدار مع الفئة المحلية (بغض النظر عن ثابت أم لا) 26 ثانية واستغرق الإصدار مع فئة مجهولة مجهولة وظيفيا 2 دقيقة 20 ثانية.

فيما يتعلق بالأداء ، يجب أن تفكر في ما إذا كان ينبغي إنشاء فئة داخلية أم لا على الإطلاق.

مثال على الممارسة السيئة هو شيء مثل:

public List<String> someMethod() {
       return new ArrayList<String>() {{
                      add("Item one");
                      add("Item two");
              }};
}

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

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

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

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