سؤال

في إشارة إلى بلدي سؤال سابق حول الكائنات غير المكتملة, ، لدي سؤال آخر. كما أشار جون سكيت ، هناك حاجز ذاكرة ضمني في نهاية مُنشئ يتأكد من ذلك final الحقول مرئية لجميع المواضيع. ولكن ماذا لو استدعى مُنشئ مُنشئًا آخر ؛ هل هناك حاجز ذاكرة في نهاية كل منهم ، أو فقط في نهاية الحاجز الذي تم استدعاؤه في المقام الأول؟ هذا هو ، عندما يكون الحل "الخاطئ":

public class ThisEscape {
    public ThisEscape(EventSource source) {
        source.registerListener(
            new EventListener() {
                public void onEvent(Event e) {
                    doSomething(e);
                }
            });
    }
}

وسيكون الصحيح إصدار طريقة المصنع:

public class SafeListener {
    private final EventListener listener;

    private SafeListener() {
        listener = new EventListener() {
            public void onEvent(Event e) {
                doSomething(e);
            }
        }
    }

    public static SafeListener newInstance(EventSource source) {
        SafeListener safe = new SafeListener();
        source.registerListener(safe.listener);
        return safe;
    }
}

هل سيعمل التالي أيضًا أم لا؟

public class MyListener {
    private final EventListener listener;

    private MyListener() {
        listener = new EventListener() {
            public void onEvent(Event e) {
                doSomething(e);
            }
        }
    }

    public MyListener(EventSource source) {
        this();
        source.register(listener);
    }
}

تحديث: السؤال الأساسي هو ذلك this() مضمون في الواقع مكالمة المُنشئ الخاص أعلاه (وفي هذه الحالة سيكون هناك الحاجز الذي سيكون مقصودًا وكل شيء آمنًا) ، أم أنه من الممكن أن يحصل المنشئ الخاص مضمون في الجمهور كتحسين لحفظ حاجز ذاكرة واحد (في هذه الحالة لن يكون هناك عائق حتى في نهاية المنشئ العام)؟

هي قواعد this() تم تعريفه بالضبط في مكان ما؟ إذا لم يكن الأمر كذلك ، فأعتقد أنه يجب علينا افتراض أنه مسموح بمنشئات متسلسلة ، وربما بعض JVMs أو ربما حتى javacS يفعلون ذلك.

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

المحلول

أعتقد أنه آمن كما ينص نموذج ذاكرة Java على ما يلي:

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

نصائح أخرى

يعتبر كائن تهيئته بالكامل عندما ينتهي مُنشئه.

هذا ينطبق أيضا على المُنشئين بالسلاسل.

إذا كان عليك التسجيل في المُنشئ ، حدد المستمع على أنه فئة داخلية ثابتة. هذا آمن.

الإصدار الثاني غير صحيح ، لأنه يسمح بالإشارة "هذا" للهروب من عملية البناء. إن الحصول على "هذا" يبرر ضمانات سلامة التهيئة التي تمنح الحقول النهائية سلامتها.

لمعالجة السؤال الضمني ، يحدث الحاجز في نهاية البناء فقط في نهاية بناء الكائن. الحدس الذي يقدمه القارئ الذي يقدمه حول التحديد هو مفيد ؛ من منظور نموذج ذاكرة Java ، لا توجد حدود الطريقة.

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


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

أعتقد أن المترجم سيضيف حاجز الذاكرة في نهاية كل مُنشئ. المشكلة لا تزال موجودة: أنت تمر this الإشارة إلى التعليمات البرمجية الأخرى (ربما مؤشرات ترابط أخرى) قبل أن يتم بناؤها بالكامل-وهذا أمر سيء-، ولكن إذا كان البناء الوحيد المتبقي هو تسجيل المستمع ، فإن حالة الكائن مستقرة كما ستكون على الإطلاق.

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

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

يمكن للهروب مرجع الكائن في C-TOR نشر كائن تم إنشاؤه بشكل غير مكتمل. هذا صحيح حتى إذا كان المنشور هو البيان الأخير في المُنشئ.

قد لا يتصرف Safelistener الخاص بك بشكل جيد في بيئة متزامنة ، حتى لو تم إجراء C-TOR INNINing (وهو ما أعتقد أنه ليس كذلك-فكر في إنشاء كائنات باستخدام الانعكاس عن طريق الوصول إلى C-TOR).

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