مقدمة: خطأ قد ترتكبه الآن
\n\nتخيل الموقف: أنت تكتب بلغة Java، تستخدم التعدادات (enum) وتحتاج لمقارنة قيمتين. تكتب تلقائياً if (day == Day.MONDAY). أو ربما if (day.equals(Day.MONDAY)). فأي الخيارين صحيح؟ وهل هناك فرق أصلاً؟
هذا السؤال هو من أكثر الأسئلة شيوعاً على Stack Overflow. آلاف المطورين (من المبتدئين إلى كبار المطورين) تساءلوا عنه. قد يبدو الأمر تافهاً. لكن خلف هذا "التفاهة" يكمن فهم عميق لكيفية عمل JVM، وكيفية بناء enum، ولماذا الأمور في Java ليست دائماً واضحة.
\n\nفي هذه المقالة، سنحسم الأمر مرة وإلى الأبد: كيف تقارن enum في Java بشكل صحيح، ومتى تستخدم ==، ومتى تستخدم equals()، ولماذا أحد هذين الخيارين هو دائماً الخيار الأفضل تقريباً.
إجابة مختصرة لغير الصبورين
\n\nإذا كنت تريد الإجابة الآن — استخدم ==.
لكن! قبل أن تغلق المقالة، دعنا نفهم لماذا هذا هو الحال، وما هي المخاطر الخفية التي قد تواجهك. لأن الشيطان، كما هو الحال دائماً، في التفاصيل.
\n\nلماذا enum ليس مجرد مجموعة من الثوابت؟
\n\nلفهم الفرق بين == و equals()، عليك أن تتذكر ما هو enum في Java حقاً.
كل enum هو فئة كاملة، ترث ضمنياً من java.lang.Enum. كل ثابت من enum هو مثيل ثابت ونهائي من هذه الفئة. JVM يضمن أنه لكل قيمة enum يوجد كائن واحد فقط في الذاكرة.
انظر إلى هذا الكود:
\n\npublic enum Day {\n MONDAY,\n TUESDAY,\n WEDNESDAY,\n THURSDAY,\n FRIDAY,\n SATURDAY,\n SUNDAY\n}\n\nعندما يقوم JVM بتحميل هذا enum، فإنه ينشئ 7 كائنات بالضبط. Day.MONDAY هو دائماً نفس الكائن. دائماً. وهذه هي النقطة الأساسية.
المقارنة باستخدام ==: لماذا تعمل؟
\n\nعامل == في Java يقارن المراجع للكائنات. لا ينظر إلى المحتوى — بل يتحقق مما إذا كان المتغيران يشيران إلى نفس الكائن في الذاكرة.
نظراً لأن JVM يضمن تفرد كل مثيل من enum، فإن المقارنة باستخدام == لـ enum تعمل بشكل لا تشوبه شائبة:
public class EnumComparison {\n public static void main(String[] args) {\n Day today = Day.WEDNESDAY;\n Day anotherDay = Day.WEDNESDAY;\n \n // كلا المتغيرين يشيران إلى نفس الكائن في الذاكرة\n System.out.println(today == anotherDay); // true\n \n // مقارنة مع ثابت آخر\n System.out.println(today == Day.MONDAY); // false\n }\n}\n\nالنتيجة:
\ntrue\nfalse\n\nكل شيء بسيط وأنيق. لكن دعنا نرى ما يحدث تحت الغطاء.
\n\nلماذا هذا آمن؟ ضمانات JVM
\n\nمواصفات لغة Java (JLS 8.9) تضمن أن كل قيمة enum تتم تهيئتها مرة واحدة فقط عند تحميل الفئة. لا يمكنك باستخدام الانعكاس (reflection) أو التسلسل (serialization) أو الاستنساخ (cloning) إنشاء نسخة مكررة. حتى لو حاولت استخدام new — سيعطيك المترجم خطأ.
لذلك، == لـ enum ليس فقط "يعمل"، بل هو أسرع وأضمن طريقة للمقارنة.
المقارنة باستخدام equals(): تعمل، لكن مع بعض التحفظات
\n\nطريقة equals() تعمل أيضاً. فئة Enum تعيد تعريف equals()، وداخلياً تستخدم ==:
// الكود الحقيقي من java.lang.Enum\npublic final boolean equals(Object other) {\n return this == other;\n}\n\nأي أن استدعاء day.equals(Day.MONDAY) في النهاية يفعل نفس الشيء مثل day == Day.MONDAY. لكن هناك فرق مهم:
مشكلة null
\n\nإذا كان المتغير الخاص بك قد يك