استخدام "هذا" كمعلمة لاستدعاء الأسلوب في المُنشئ

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

سؤال

لدي منشئ مثل ما يلي:

public Agent(){

    this.name = "John";
    this.id = 9;
    this.setTopWorldAgent(this, "Top_World_Agent", true);

}

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

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

المحلول

يمكنك تمرير هذا إلى الأساليب، ولكن لا يمكن أن يكون setTopWorldAgent() مجردًا.لا يمكنك إجراء مكالمة افتراضية في المُنشئ.

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

في Java، يمكنك الحصول على سلوك مفاجئ مع المنشئ والفئات المشتقة - هنا مثال

http://en.wikipedia.org/wiki/Virtual_functions#Java_3

إذا كنت معتادًا على لغة C# أو C++، فقد تعتقد أنه من الآمن استدعاء الوظائف الافتراضية وعدم استدعاء الوظائف التي تم تجاوزها.في Java، يتم إجراء الاستدعاء الظاهري على الرغم من عدم إنشاء الفئة المشتقة بشكل كامل.

إذا لم يكن هذا هو ما يحدث، فمن المفترض أن تتم تهيئة جميع أجزاء هذا التي يحتاجها setTopWorldAgent() - إذا لم يكن الأمر كذلك، فمن المحتمل أن يكون أحد أعضاء هذا هو الذي يحتاج إلى التهيئة.

يحرر:أعتقد أن هذا كان C#

نصائح أخرى

بدافع الفضول، لماذا تقوم بتمرير "هذا" إلى وظيفة عضو من نفس الفئة؟يمكن لـ setTopWorldAgent() استخدام "هذا" مباشرة.لا يبدو أن المُنشئ أو setTopWorldAgent() الخاص بك ثابتان، لذلك لست متأكدًا من سبب تمرير وظيفة عضو إلى شيء يمكنه الوصول إليه بالفعل.

إلا إذا كنت في عداد المفقودين شيء...

لماذا أراد setTopWorldAgent يحتاج this كحجة؟بناءً على الاستدعاء، فهي طريقة مثيل، لذا يمكن الرجوع إليها this دون الحاجة إلى تلقيها كمعلمة.

أعتقد أكثر من ذلك، لماذا تقوم بتمرير "هذا" كمعلمة إلى طريقة في "هذا"؟

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

public class Test {
  public Test() {
    this.hi(this);
  }
  public void hi(Test t) {
    System.out.println(t);
  }

  public static void main(String[] args) throws Exception {
    Test t = new Test();
  }
}

بالنظر إلى أن setTopWorldAgent يبدو وكأنه أسلوب مثيل، فلماذا تمرر هذا إليه على أي حال؟

لا ينبغي أن يكون "هذا" فارغًا أبدًا.هل أنت متأكد من أنه تم طرح الاستثناء بسبب ذلك؟

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

يجب أن يكون الخطأ في مكان آخر لأن الكود أعلاه يعمل بالتأكيد، ويجب أن يكون المرجع الفارغ شيئًا آخر.

إذا كان وكيلك يقوم بتنفيذ ITopWorldAgent، فيجب عليك القيام بذلك بالفعل:


Agent agent = new Agent("John", 9);
agent.setTopWorldAgent(agent, "Top_World_Agent", true);

إذا لم يكن الأمر كذلك، فلماذا تقوم بتعيين شيء ما بالطريقة التي أنت عليها؟

أفترض أن شيئًا ما في طريقة setTopWorldAgent يستخدم قيمة لم تتم تهيئتها بعد في مُنشئك.

this ليست فارغة، وهذا أمر مؤكد.لقد تم تخصيصها.

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

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

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

في هذه الحالة بالطبع تكون الوسيطة غير ضرورية لأن الطريقة تحتوي بالفعل على إشارة إلى "هذا".

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

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