سؤال

لقد مررت عبر الفصل الذي تم إعداده على النحو التالي:

public class MyClass {

  private static boolean started = false;

  private MyClass(){
  }

  public static void doSomething(){
    if(started){
      return;
    }
    started = true;
    //code below that is only supposed to run
    //run if not started
  }
}

ما أفهمه مع الأساليب الثابتة هو أنه لا يجب عليك استخدام متغيرات الفئة فيها إلا إذا كانت ثابتة ولا تتغير.بدلا من ذلك يجب عليك استخدام المعلمات.سؤالي هو لماذا لا ينقطع هذا عند الاتصال به عدة مرات عن طريق القيام بـ MyClass.doSomething().يبدو لي أنه لا ينبغي أن يعمل ولكنه يعمل.سيتم تمرير عبارة if مرة واحدة فقط.

فهل يمكن لأحد أن يشرح لي لماذا لا ينكسر هذا؟

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

المحلول

ووdoSomething() طريقة وstarted متغير كلاهما ثابت، حتى لا يكون هناك نسخة واحدة فقط من متغير ويمكن الوصول إليها من doSomething(). ويطلق على doSomething() أول مرة، started غير صحيح، لذلك يحدد started إلى true ثم لا ... حسنا، شيء. وانه دعا مرة الثانية واللاحقة، started غير صحيح، لذلك فإنه يعود دون أن تفعل أي شيء.

نصائح أخرى

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

ما يجب أن يحدث هو:

  1. تم إجراء المكالمة الأولى.تمت تهيئة الفصل، والبدء خاطئ.
  2. افعل شيئا يسمى.إذا فشل الكود وتجاوزه.تم تعيين start على true ويتم تشغيل التعليمات البرمجية الأخرى.
  3. يتم استدعاء doSomething مرة أخرى.إذا مر وتوقف التنفيذ.

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

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

public class MyClass {

  private static AtomicBoolean started = new AtomicBoolean(false);

  private MyClass(){
  }

  public static void doSomething(){
    boolean oldValue = started.getAndSet(true);
    if (oldValue)
      return;
    }

    //code below that is only supposed to run
    //run if not started
  }
}

وهذا يجب أن يكون الخيط آمنة، ومزامنة AtomicBoolean getAndSet.

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

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

<اقتباس فقرة>   

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

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

<اقتباس فقرة>   

وبدلا من ذلك يجب عليك استخدام المعلمات.

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

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

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

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

إذا حاولت الوصول إلى متغير عضو غير ثابت:

private int foo = 0;

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

started is false - initial state.
MyClass.doSomething() - statered is now true
MyClass.doSomething() - started is STILL true

MyClass foo = new MyClass();
foo.started -> it's STILL true, because it's static
foo.doSomething() - not sure you can do this in Java, but if you can, it's be STILL TRUE!

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

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

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

ورمز أعلاه يعمل بشكل جيد تماما (ما لم يتم تشغيله في بيئة مؤشرات). لماذا تعتقد أنه يجب كسر؟

<اقتباس فقرة>   

وأفهمه مع أساليب ثابتة هي التي يجب أن لا تستخدم متغيرات الطبقة فيها ما لم تكن ثابتة، وليس لتغيير

واعتقد أعضاء ثابت فقط يمكن الوصول إليها. ليس من الضروري أن يكون ثابت!

<اقتباس فقرة>   

وسؤالي هو لماذا هذا لا كسر عندما دعا عدة مرات عن طريق القيام MyClass.doSomething (). يبدو لي مثل ذلك لا يجب أن تعمل ولكن لا. وسوف تذهب فقط تمرير إذا بيانا مرة واحدة

ولكل منطق القائمة. فقط المكالمة الأولى تشغيل جزء //code to be run

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