هنگام برنامه نویسی، ما اغلب با نیاز به محدود کردن مجموعه مقادیر معتبر برای یک نوع داده خاص روبرو هستیم. بنابراین، به عنوان مثال، روز هفته می تواند 7 مقدار مختلف، ماه سال می تواند 12، و فصل می تواند 4 مقدار داشته باشد. برای حل چنین مشکلاتی، بسیاری از زبان های برنامه نویسی تایپ شده ایستا یک نوع داده خاص ارائه می دهند - شمارش ( اعضای Enum نمونه هایی
عناصر نمونه هایی از کلاس
enum
). Enumeration بلافاصله در جاوا ظاهر نشد. یک ساختار زبان تخصصی enum
با شروع نسخه 1.5 معرفی شد. تا این مرحله، برنامه نویسان از روش های دیگری برای پیاده سازی شمارش ها استفاده می کردند.
ساخت enum
بیایید با یک مثال شروع کنیم.enum
بیایید نوع داده را برای ذخیره زمان سال با استفاده از :
enum Season { WINTER, SPRING, SUMMER, AUTUMN }
خوب، یک مثال ساده از کاربرد آن:
Season season = Season.SPRING;
if (season == Season.SPRING) season = Season.SUMMER;
System.out.println(season);
در نتیجه SUMMER در کنسول چاپ می شود . من فکر می کنم که مثال واضح است و نیازی به توضیح ندارد.
Enum یک کلاس است
با اعلان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
وراثت واقعی به طور خودکار توسط کامپایلر جاوا برای ما انجام می شود. در مرحله بعد، بیایید موافقت کنیم که کلاس ایجاد شده توسط کامپایلر را برای پیاده سازی شمارش -class enum
و مقادیر احتمالی نوع شمارش شده را به عنوان enum
عناصر -a فراخوانی کنیم.
اعضای Enum نمونه هایی enum
از یک کلاس هستند که به صورت ایستا قابل دسترسی هستند
عناصر نمونه هایی از کلاس enum Season (WINTER, SPRING и т.д.)
هستند که به صورت ایستا قابل دسترسی هستند . در دسترس بودن استاتیک آنها به ما اجازه می دهد تا با استفاده از عملگر مقایسه مرجع مقایسه انجام دهیم . مثال: enum
Season
==
Season season = Season.SUMMER;
if (season == Season.AUTUMN) season = Season.WINTER;
نام و شماره سریال عنصر enum
همانطور که قبلا ذکر شد، هرenum
کلاسی ارث می برد 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 برابر با Season.WINTER
. لطفاً توجه داشته باشید که اگر عنصر پیدا نشود، یک IllegalArgumentExceptionname
پرتاب میشود و اگر برابر باشد null
، یک NullPointerException پرتاب میشود . به هر حال، این اغلب فراموش می شود. بنا به دلایلی، بسیاری قاطعانه متقاعد شده اند که اگر تابعی یک آرگومان را بگیرد و تحت شرایط خاصی یک IllegalArgumentException پرتاب کند ، پس هنگام ارسال آن به آنجا ، مطمئناً یک IllegalArgumentExceptionnull
نیز پرتاب خواهد شد . اما این در کنار موضوع است. بیا ادامه بدهیم. دریافت تمام عناصر یک شمارش گاهی اوقات لازم است فهرستی از تمام عناصر یک کلاس در زمان اجرا تهیه کنید. برای این منظور، کامپایلر یک متد در هر کلاس ایجاد می کند . مثال استفاده: enum
enum
public static EnumClass[] values()
System.out.println(Arrays.toString(Season.values()));
خروجی زیر را دریافت می کنیم:
[WINTER, SPRING, SUMMER, AUTUMN]
توجه داشته باشید که نه متد valueOf()
و نه متد values()
در کلاس تعریف نشده است java.lang.Enum
. enum
در عوض، هنگام کامپایل شدن -class به طور خودکار توسط کامپایلر اضافه می شوند . افزودن متدهای خود به enum
کلاس - شما این فرصت را دارید که روشهای خود را هم به enum
- کلاس و هم به عناصر آن اضافه کنید: یکسان، اما با چندشکلی: آخرین مثال استفاده از وراثت را در enum
. بیشتر در این مورد بعدا. وراثتenum
در جاوا enum
به شما اجازه می دهد تا یک سلسله مراتب کلاس را پیاده سازی کنید، اشیاء آن در یک نمونه ایجاد می شوند و به صورت ایستا قابل دسترسی هستند. در این مورد، عناصر enum
می توانند شامل سازنده های خود باشند. بیایید مثالی بزنیم: در اینجا یک شمارش Type
با سه عنصر INT
و INTEGER
. STRING
کامپایلر کلاس ها و اشیاء زیر را ایجاد می کند:
Type
- کلاس برگرفته ازjava.lang.Enum
INT
- شی از کلاس 1 مشتق شده ازType
INTEGER
- شی از کلاس 2 مشتق شده ازType
STRING
- شی از کلاس 3 مشتق شده از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
.
کلاس enum با وراثت دکامپایل شد
برای تایید موارد فوق، نتیجه ی کامپایل کردن شمارش را نیزType
از مثال بالا ارائه می دهیم:
شمارش ها و چندشکلی پارامتری
خواننده ممکن است تعجب کند: " چرا شمارش نوع بالا از ژنریک استفاده نمی کند؟ " واقعیت این است که در جاوا استفاده از ژنریکenum
ممنوع است. بنابراین مثال زیر کامپایل نخواهد شد:
enum Type<T> {}
مطالعه بیشتر
برای درک عمیق تر از نحوه کار enumerations در جاوا، توصیه می کنم با کد منبع کلاس آشنا شویدjava.lang.Enum
و همچنین از Decompiler Jad برای مطالعه کدهای تولید شده استفاده کنید. علاوه بر این، مطالعه کد منبع کتابخانه جاوا برای درک تعداد مکانیسمهای موجود در جاوا کاملاً ضروری است و به عنوان مرجعی برای طراحی شیگرا مفید است. لینک منبع اصلی: http://alexander.lds.lg.ua/
GO TO FULL VERSION