عند البرمجة، غالبًا ما نواجه الحاجة إلى تحديد مجموعة القيم الصالحة لنوع معين من البيانات. لذلك، على سبيل المثال، يمكن أن يحتوي يوم الأسبوع على 7 قيم مختلفة، ويمكن أن يحتوي شهر السنة على 12، ويمكن أن يحتوي الموسم على 4. ولحل مثل هذه المشكلات، توفر العديد من لغات البرمجة المكتوبة بشكل ثابت نوع بيانات خاصًا - التعداد ( أعضاء التعداد هم مثيلات
العناصر
enum
). لم يظهر التعداد في Java على الفور. تم تقديم بنية لغة متخصصة enum
بدءًا من الإصدار 1.5. حتى هذه اللحظة، استخدم المبرمجون طرقًا أخرى لتنفيذ التعدادات.
بناء التعداد
لنبدأ بمثال. دعنا نصفenum
نوع البيانات لتخزين الموسم باستخدام:
enum Season { WINTER, SPRING, SUMMER, AUTUMN }
حسنًا، مثال بسيط على استخدامه:
Season season = Season.SPRING;
if (season == Season.SPRING) season = Season.SUMMER;
System.out.println(season);
ونتيجة لذلك سيتم طباعة SUMMER على وحدة التحكم . أعتقد أن المثال واضح ولا يحتاج إلى شرح.
التعداد هو فئة
من خلال الإعلانenum
، نقوم ضمنيًا بإنشاء فئة مشتقة من java.lang.Enum
. تقليديا، البناء enum Season { ... }
يعادل class Season extends java.lang.Enum { ... }
. وعلى الرغم من أن المترجم لا يسمح لنا بوراثة منا بشكل صريح java.lang.Enum
، إلا أنه لا يزال من السهل التحقق من enum
توريثه باستخدام reflection
:
System.out.println(Season.class.getSuperclass());
سيتم عرض ما يلي على وحدة التحكم:
class java.lang.Enum
يتم تنفيذ الميراث الفعلي تلقائيًا لنا بواسطة مترجم Java. بعد ذلك، دعونا نتفق على استدعاء الفئة التي أنشأها المترجم لتنفيذ التعداد بـ enum
-class، والقيم المحتملة للنوع المذكور enum
كعناصر -a.
أعضاء التعداد هم مثيلات enum
لفئة يمكن الوصول إليها بشكل ثابت
العناصر enum Season (WINTER, SPRING и т.д.)
هي مثيلات يمكن الوصول إليها بشكل ثابت enum
من -class Season
. يتيح لنا توفرها الثابت إجراء مقارنات باستخدام عامل المقارنة المرجعي ==
. مثال:
Season season = Season.SUMMER;
if (season == Season.AUTUMN) season = Season.WINTER;
الاسم والرقم التسلسلي لعنصر التعداد
كما ذكرنا سابقًا، فإن Anyenum
-class يرث java.lang.Enum
، والذي يحتوي على عدد من التوابع المفيدة لجميع التعدادات. مثال:
Season season = Season.WINTER;
System.out.println("season.name()=" + season.name() + " season.toString()=" + season.toString() + " season.ordinal()=" + season.ordinal());
سيكون الإخراج:
season.name()=WINTER season.toString()=WINTER season.ordinal()=0
الأساليب name()
، toString()
وتظهر هنا ordinal()
. دلالات الأساليب واضحة. تجدر الإشارة إلى أن هذه الأساليب enum
موروثة من الفصل java.lang.Enum
. الحصول على عنصر enum
من خلال تمثيل السلسلة لاسمه في كثير من الأحيان تنشأ مهمة الحصول على عنصر enum
من خلال تمثيل السلسلة الخاصة به. لهذه الأغراض، في كل enum
فئة، يقوم المترجم تلقائيًا بإنشاء طريقة ثابتة خاصة: public static EnumClass valueOf(String name)
والتي تقوم بإرجاع عنصر التعداد EnumClass
باسم يساوي name
. مثال الاستخدام:
String name = "WINTER";
Season season = Season.valueOf(name);
نتيجة لتنفيذ الكود، سيكون متغير الموسم مساويًا لـ Season.WINTER
. يرجى ملاحظة أنه إذا لم يتم العثور على العنصر، فسيتم طرح IllegalArgumentException ، وإذا كان name
متساويًا null
، فسيتم طرح NullPointerException . بالمناسبة، غالبا ما يتم نسيان هذا. لسبب ما، كثيرون مقتنعون تمامًا أنه إذا أخذت دالة وسيطة واحدة وفي ظل ظروف معينة قامت بإلقاء IllegalArgumentException ، فعند تمريرها إلى هناك ، سيتم بالتأكيد طرح IllegalArgumentExceptionnull
أيضًا . ولكن هذا خارج عن الموضوع. فلنكمل. الحصول على كافة عناصر التعداد في بعض الأحيان تحتاج إلى الحصول على قائمة بجميع عناصر -class في وقت التشغيل. لهذه الأغراض، يقوم المترجم بإنشاء طريقة في كل -class . مثال الاستخدام: enum
enum
public static EnumClass[] values()
System.out.println(Arrays.toString(Season.values()));
نحصل على الإخراج التالي:
[WINTER, SPRING, SUMMER, AUTUMN]
لاحظ أنه لم يتم تعريف أي طريقة valueOf()
ولا طريقة values()
في الفصل java.lang.Enum
. بدلاً من ذلك، يتم إضافتها تلقائيًا بواسطة المترجم عند enum
تجميع الفئة. إضافة أساليبك الخاصة إلى enum
-class لديك الفرصة لإضافة أساليبك الخاصة إلى كل من enum
-class وعناصره: نفس الشيء، ولكن مع تعدد الأشكال: يوضح المثال الأخير استخدام الميراث في enum
. المزيد عن هذا لاحقا. يسمح لك الوراثةenum
في Java enum
بتنفيذ تسلسل هرمي للفئة، حيث يتم إنشاء كائناتها في مثيل واحد ويمكن الوصول إليها بشكل ثابت. في هذه الحالة، enum
يمكن أن تحتوي العناصر على مُنشئاتها الخاصة. لنعطي مثالا: هنا نعلن عن تعداد بثلاثة Type
عناصر INT
و INTEGER
. STRING
سيقوم المترجم بإنشاء الفئات والكائنات التالية:
Type
- فئة مشتقة منjava.lang.Enum
INT
- كائن من الدرجة الأولى مشتق منType
INTEGER
- كائن من الدرجة الثانية مشتق منType
STRING
- كائن من الدرجة الثالثة مشتق منType
Object parse(String)
ومنشئ Type(..., boolean)
. INT
في الوقت نفسه ، INTEGER
توجد كائنات الفئات STRING
في نسخة واحدة ويمكن الوصول إليها بشكل ثابت. يمكنك التحقق من ذلك:
System.out.println(Type.class);
System.out.println(Type.INT.getClass() + " " + Type.INT.getClass().getSuperclass());
System.out.println(Type.INTEGER.getClass() + " " + Type.INTEGER.getClass().getSuperclass());
System.out.println(Type.STRING.getClass() + " " + Type.STRING.getClass().getSuperclass());
نحصل على الإخراج التالي:
class Type
class Type$1 class Type
class Type$2 class Type
class Type$3 class Type
يمكن ملاحظة أن المترجم أنشأ فئة Type
و 3 nested
فئات مشتقة من Type
.
فئة التعداد المنفصلة مع الميراث
ولتأكيد ما سبق نقدم أيضاً نتيجة فك التعدادType
من المثال أعلاه:
التعدادات وتعدد الأشكال البارامترية
قد يتساءل القارئ: " لماذا لا يستخدم تعداد النوع أعلاه الأسماء العامة؟ " الحقيقة هي أن استخدام الأدوية الجنيسةenum
محظور في Java. لذلك لن يتم تجميع المثال التالي:
enum Type<T> {}
المزيد من الدراسة
لفهم أعمق لكيفية عمل التعدادات في Java، أوصي بالتعرف على الكود المصدري للفئةjava.lang.Enum
، وكذلك استخدام برنامج Jad decompiler لدراسة الكود الذي تم إنشاؤه. علاوة على ذلك، فإن دراسة الكود المصدري لمكتبة Java أمر ضروري للغاية لفهم عدد الآليات التي تعمل في Java وهي مفيدة كمرجع للتصميم الموجه للكائنات. رابط المصدر الأصلي: http://alexander.lds.lg.ua/
GO TO FULL VERSION