count
كان الحقل ثابتًا في Counter
الفئة، فهذا يعني أنه يمكنك الإشارة إلى المتغير بالتعبير التالي: Counter.count
. وبطبيعة الحال، يجب أن تؤخذ في الاعتبار معدلات الوصول. على سبيل المثال، private
تتوفر الحقول فقط داخل الفئة التي تم الإعلان عنها. والحقول protected
متاحة لجميع الفئات داخل الحزمة، وكذلك لجميع فئاتها الفرعية خارج الحزمة. لنفترض أن Counter
الفصل لديه طريقة ثابتة increment()
تتمثل مهمتها في زيادة count
الحقل. لاستدعاء هذه الطريقة، يمكنك استخدام Counter.increment()
. ليست هناك حاجة لإنشاء مثيل للفئة Counter
للوصول إلى حقل أو أسلوب ثابت. هذا هو الفرق الأساسي بين المتغيرات والأساليب الثابتة (الفئة) والمتغيرات والأساليب غير الثابتة (المثيل). ملاحظة مهمة. لا تنس أن الأعضاء الثابتين في الفصل ينتمون مباشرة إلى الفصل، وليس إلى أي مثيل للفئة. أي أن قيمة المتغير الثابت count
ستكون هي نفسها لجميع Counter
الكائنات. في هذه المقالة، سنلقي نظرة على الجوانب الأساسية لاستخدام المعدل الثابت في Java، بالإضافة إلى بعض الميزات التي ستساعدك على فهم مفاهيم البرمجة الأساسية.
ما يجب أن يعرفه كل مبرمج عن المعدل الثابت في Java.
في هذا القسم، سنلقي نظرة على الجوانب الرئيسية لاستخدام الأساليب والحقول والفئات الثابتة. لنبدأ بالمتغيرات.-
لا يمكنك الوصول إلى الأعضاء غير الثابتين في فئة ضمن سياق ثابت، مثل أسلوب ثابت أو كتلة. سيؤدي تجميع الكود أدناه إلى حدوث خطأ:
public class Counter { private int count; public static void main(String args []) { System.out.println(count); // Compile time error } }
وهذا أحد الأخطاء الأكثر شيوعًا التي يرتكبها مبرمجو Java، وخاصة المبتدئين. نظرًا لأن
main
الطريقة ثابتة والمتغيرcount
ليس كذلك، فإن استخدامprintln
الطريقة داخلmain
الطريقة سيؤدي إلى حدوث "خطأ في وقت الترجمة". -
على عكس المتغيرات المحلية، فإن الحقول والأساليب الثابتة ليست موجودة
thread safe
في Java. من الناحية العملية، يعد هذا أحد الأسباب الأكثر شيوعًا لمشاكل الأمان في البرمجة متعددة الخيوط. مع الأخذ في الاعتبار أن كل مثيل لفئة يشير إلى نفس النسخة من متغير ثابت، فإن مثل هذا المتغير يحتاج إلى الحماية أو "التأمين" بواسطة الفئة. لذلك، عند استخدام المتغيرات الثابتة، تأكد من أنها صحيحةsynchronized
لتجنب مشاكل مثلrace conditions
. -
تتمتع الأساليب الثابتة بميزة عملية تتمثل في عدم الحاجة إلى إنشاء كائن جديد في كل مرة تريد الاتصال بها. يمكن استدعاء الطريقة الثابتة باستخدام اسم الفئة التي تعلن عنها. ولهذا السبب تعتبر هذه الطرق مثالية للطرق
factory
والأساليبutility
. يعد الفصلjava.lang.Math
مثالًا رائعًا: جميع أساليبه تقريبًا ثابتة. يتم تمييز فئات الأدوات المساعدة في Javafinal
لنفس السبب. -
هناك نقطة أخرى مهمة وهي أنه لا يمكنك تجاوز (
@Override
) الطرق الثابتة. إذا قمت بالإعلان عن مثل هذه الطريقة في ملفsubclass
، أي طريقة بنفس الاسم والتوقيع، فما عليك سوى "إخفاء" طريقةsuperclass
بدلاً من تجاوزها. تُعرف هذه الظاهرة باسمmethod hiding
. هذا يعني أنه إذا تم الإعلان عن طريقة ثابتة في كل من الفئتين الأصل والطفل، فستعتمد الطريقة التي يتم استدعاؤها دائمًا على نوع المتغير في وقت الترجمة. على عكس تجاوز الطريقة، لن يتم تنفيذ مثل هذه الأساليب عند تشغيل البرنامج. دعونا نفكر في مثال:class Vehicle { public static void kmToMiles(int km) { System.out.println("Inside the parent class / static method"); } } class Car extends Vehicle { public static void kmToMiles(int km) { System.out.println("Inside the child class / static method"); } } public class Demo { public static void main(String args []) { Vehicle v = new Car(); v.kmToMiles(10); } }
إخراج وحدة التحكم:
داخل الفئة الأصل/الطريقة الثابتة
يوضح الكود بوضوح أنه على الرغم من أن الكائن هو
Car
، يتم استدعاء الطريقة الثابتة فيVehicle
الفصل، حيث تم استدعاء الطريقة في وقت الترجمة. ولاحظ أنه لم تكن هناك أخطاء في التجميع! -
علاوة على ذلك، بخلاف فئات المستوى الأعلى، يمكنك إعلان الفئات ثابتة. تُعرف هذه الفئات باسم
nested static classes
. وهي مفيدة لتوفير تماسك أفضل. من الأمثلة الصارخة على فئة ثابتة متداخلةHashMap.Entry
، وهي عبارة عن بنية بيانات بداخلهاHashMap
. تجدر الإشارة إلى أنه، مثل الفئات الداخلية، يتم الإعلان عن الفئات المتداخلة الثابتة في ملف .class منفصل. وبالتالي، إذا قمت بتعريف خمس فئات متداخلة في فئتك الرئيسية، فسيكون لديك 6 ملفات بامتداد .class. مثال آخر هو الإعلان الخاص بناComparator
، مثل مقارنة العمر (AgeComparator
) فيEmployee
الفصل. -
يمكن أيضًا تحديد المُعدِّل الثابت في كتلة ثابتة، تُعرف باسم "كتلة التهيئة الثابتة"، والتي يتم تنفيذها عند تحميل الفصل. إذا لم تعلن عن مثل هذه الكتلة، تقوم Java بجمع كافة الحقول الثابتة في قائمة واحدة وتهيئتها عند تحميل الفصل. لا يمكن للكتلة الثابتة طرح الاستثناءات المحددة، ولكن يمكنها طرح الاستثناءات غير المحددة. في هذه الحالة
ExceptionInInitializerError
سيحدث. من الناحية العملية، أي استثناء يحدث أثناء تهيئة الحقول الثابتة سيتم تغليفه بهذا الخطأ بواسطة Java. وهذا أيضًا هو السبب الأكثر شيوعًا لـNoClassDefFoundError
، لأن الفصل لن يكون في الذاكرة عند الرجوع إليه. -
من المفيد معرفة أن الطرق الثابتة ترتبط في وقت الترجمة، على عكس ربط الطرق الافتراضية أو غير الثابتة، التي ترتبط في وقت التشغيل عند استدعائها على كائن حقيقي. وفقًا لذلك، لا يمكن تجاوز الأساليب الثابتة في Java، نظرًا لأن تعدد الأشكال لا ينطبق عليها في وقت التشغيل. يعد هذا قيدًا مهمًا يجب مراعاته عند الإعلان عن طريقة ثابتة. إن القيام بذلك يكون منطقيًا فقط عندما لا تكون هناك قدرة أو حاجة لتجاوز الطريقة في فئة فرعية. تعد أساليب المصنع وأساليب المنفعة أمثلة جيدة على الاستخدام السليم للمعدل الثابت. يشير جوشوا بلوخ إلى العديد من المزايا التي تتمتع بها أساليب المصنع الثابتة مقارنة بالمنشئين في كتابه Java الفعال، وهو أمر إلزامي لكل مبرمج Java.
-
تعد التهيئة جانبًا مهمًا للكتلة الثابتة. تتم تهيئة الحقول أو المتغيرات الثابتة بعد تحميل الفئة في الذاكرة. ترتيب التهيئة من أعلى إلى أسفل، بنفس الترتيب الذي تم الإعلان عنه في الملف المصدر لفئة Java. نظرًا لأنه تتم تهيئة الحقول الثابتة بطريقة آمنة لمؤشر الترابط، يتم استخدام هذه العملية أيضًا لتنفيذ النمط
Singleton
. إذا كنت لا تستخدم asEnum
لسببSingleton
ما، فلديك بديل جيد. ولكن في هذه الحالة، يجب أن تأخذ في الاعتبار أن هذه ليست تهيئة "كسولة". هذا يعني أنه سيتم تهيئة الحقل الثابت حتى قبل أن "يطلب" شخص ما ذلك. إذا كان الكائن كثيف الموارد أو نادر الاستخدام، فإن تهيئته في كتلة ثابتة لن يعمل لصالحك. -
أثناء عملية التسلسل،
transient
لا يتم إجراء تسلسل للحقول الثابتة، مثل المتغيرات. في الواقع، إذا قمت بحفظ أي بيانات في حقل ثابت، فسوف تحتوي على قيمتها الأولية (الافتراضية) بعد إلغاء التسلسل. على سبيل المثال، إذا كان الحقل الثابت عبارة عن حقل ثابتint
، فستكون قيمته صفرًا بعد إلغاء التسلسل. إذا كان نوعهfloat
، فستكون القيمة 0.0. إذا كان الحقلObject
, فستكون القيمةnull
. لأكون صادقًا، يعد هذا أحد الأسئلة الأكثر شيوعًا حول التسلسل في المقابلات الخاصة بوظائف Java. لا تقم بتخزين بيانات الكائن الأساسية في حقل ثابت! -
وأخيرا، دعونا نتحدث عن الاستيراد الثابت. يحتوي هذا المعدل على الكثير من القواسم المشتركة مع
import
العبارة القياسية، ولكنه يختلف من حيث أنه يسمح لك باستيراد واحد أو كل أعضاء الفئة الثابتة. بمجرد استيراد الأساليب الثابتة، يمكن الوصول إليها كما لو تم الإعلان عنها في نفس الفئة. وبالمثل، من خلال استيراد الحقول الثابتة، يمكننا الوصول إليها دون تحديد اسم الفئة. ظهرت هذه الميزة في Java 1.5 وتعمل على تحسين إمكانية قراءة التعليمات البرمجية عند استخدامها بشكل صحيح. يتم العثور على هذا البناء في أغلب الأحيان في اختبارات JUnit، نظرًا لأن جميع مطوري الاختبار تقريبًا يستخدمون الاستيراد الثابت لطرق التأكيد، على سبيل المثالassertEquals()
ومتغيراتها المحملة بشكل زائد. -
هذا كل شئ حتى الان. يحتاج كل مبرمج Java إلى معرفة جميع جوانب المُعدِّل الثابت المذكور أعلاه. استعرضت هذه المقالة المعلومات الأساسية حول المتغيرات الثابتة والحقول والأساليب وكتل التهيئة والواردات. كما تطرقت أيضًا إلى بعض الخصائص المهمة التي لا بد من معرفتها لكتابة برامج Java وفهمها. آمل أن يتقن كل مطور استخدامه الماهر للأعضاء الثابتة، لأنه مهم جدًا للتطوير الجاد للبرمجيات."
GO TO FULL VERSION