آشنایی با Enumها
Enumerationها که به اختصار به آنها Enum نیز گفته میشود راهی برای گروهبندی مجموعهای از مقادیر ثابت هستند. گاهی اوقات نیاز داریم تا مجموعهای از مقادیر ثابتی که تغییر نمیکنند با اسمی مشخص داشته باشیم. اهمیت Enum ها را با مثال زیر میتوان درک کرد.
مثال: متدی برای محاسبه هزینه حمل و نقل بار داریم که دو پارامتر دریافت میکند: اول وزن بار و دوم نوع وسیله نقلیه:
public double transportCost(double weight, String vehicleType) { switch(vehicleType) { case "Plane": return weight * 10; case "Truck": return weight * 5; case "Ship": return weight * 1.5; default: return 0; } }
همانطور که در کد مشخص است مقدار پارامتر vehicleType باید یکی از مقادیر “هواپیما” یا “کامیون” و یا “کشتی” باشد و فقط در صورتی که مقدار این پارامتر یکی از این مقادیر باشد مقدار صحیح در متد محاسبه شده و برگردانده میشود اما نوع داده پارامتر vehicleType از نوع String است و بنابراین هر مقداری میتوان به این پارامتر داد و هیچ الزامی برای برنامهنویس وجود ندارد که حتما یکی از مقادیر Plane یا Truck یا Ship را به متد بدهد.
پس بهتر است که مجموعهای به نام Vehicle داشته باشیم که در آن مجموعه سه مقدار Plane و Truck و Ship وجود داشته باشد و سپس نوع پارامتر vehicleType را به Vehicle تغییر دهیم تا این پارامتر فقط یکی از این سه مقدار را قبول کند و راه حل این کار استفاده از Enumهاست.
تعریف و استفاده از Enumها
یک Enum را هم میتوان در یک فایل جداگانه تعریف کرد و هم درون یک کلاس. برای تعریف یک Enum در یک فایل جداگانه در ایکلیپس میتوانید از همان منویی که برای ساخت کلاس یا اینترفیس استفاده میکنید گزینه Enum را انتخاب کنید.
مثال: یک Enum به نام Vehicle در یک فایل جداگانه ایجاد کنید. مانند کلاسها، نام فایل Enum باید با نام خود آن یکی باشد پس بنابراین در فایل Vehicle.java کدهای زیر را داریم:
public enum Vehicle { PLANE, TRUCK, SHIP }
همانطور که میبینید سه مقداری که مد نظر داشتیم را در این Enum نوشتیم. مقادیر یک Enum طبق یک قرارداد باید تماما با حروف بزرگ نوشته شوند و اگر از چند کلمه تشکیل شوند باید با علامت _ کلمات را از هم جدا کرد مثل MY_VALUE
نکته دیگر وجود کاما در انتهای مقادیر است که برای تفکیک مقادیر به کار میرود البته در انتهای مقدار آخر وجود کاما الزامی نیست.
نکته جالبی که در مورد Enum ها وجود دارد این است که Enum ها یک نوع داده هستند. مثلا اگر متغیری از نوع Vehicle تعریف کنیم:
Vehicle myVehicle;
آنگاه فقط میتوان یکی از مقادیر موجود در Vehicle را به این متغیر نسبت داد.
برای استفاده از مقادیر یک Enum به صورت زیر عمل میکنیم:
نام مقدار.نام Enum
حال میخواهیم متدی که در ابتدا نوشتیم را کمی تغییر دهیم:
public double transportCost(double weight, Vehicle vehicleType) { double cost = 0; if (vehicleType == Vehicle.PLANE) cost = weight * 10; else if (vehicleType == Vehicle.TRUCK) cost = weight * 5; else if (vehicleType == Vehicle.SHIP) cost = weight * 1.5; return cost; }
همانطور که دیدید نوع پارامتر vehicleType به Vehicle تغییر یافت و بنابراین فقط میتوان مقادیر موجود در Vehicle را به این پارامتر داد.
در شروطی که نوشتیم مقدار پارامتر vehicleType را با مقادیر موجود در Vehicle مقایسه کردیم تا اگر با هر کدام از آنها برابر بود مقدار مناسب در متغیر cost قرار گیرد.
نگاهی عمیقتر به Enumها
نکتهای که باید به آن توجه داشت این است که Enumها ذاتا کلاس هستند اگرچه برای تعریف آنها از کلمه class استفاده نمیشود یا برای استفاده از آنها با دستور new از آنها شی نمیسازیم اما هر Enum به صورت ضمنی یک کلاس فرزند از کلاس Enum موجود در پکیج java.lang است.
نکته دیگر اینکه هر کدام از مقادیر موجود در یک Enum در واقع یک شی از آن Enum هستند پس میتوانند سازنده و متد و فیلد داشته باشند.
اما اگرچه Enum ها ذاتا کلاس هستند ولی Enum ها نمیتوانند از کلاس یا Enum دیگری ارثبری داشته باشند.
مثال: میخواهیم برای Enum ای که در مثالهای قبل نوشتیم یک سازنده، یک فیلد و یک متد تعریف کنیم:
public enum Vehicle { PLANE(13), TRUCK(11), SHIP(9); private int code; Vehicle(int code) { this.code = code; } public int getCode() { return code; } }
همانطور که میبینید یک فیلد با تعیینکننده دسترسی private و یک سازنده که به این فیلد مقداردهی میکند و یک متد که مقدار این فیلد را برمیگرداند در این Enum نوشتهایم.
سازندهای که برای این Enum نوشتیم دقیقا در لحظه تعریف هر ثابت در این Enum فراخوانی میشود و به همین دلیل است که در مقابل هر کدام ثابتها سازنده را فراخوانی کردیم و مقداری به آن دادیم.
سازندهای که در این Enum تعریف کردهایم بدون تعیین کننده دسترسی است چون این سازنده قرار نیست جایی خارج از این Enum فراخوانی شود و همانطور که گفتیم این سازنده فقط هنگام تعریف ثابتها و در همین Enum فراخوانی میشود لذا وجود تعیینکننده دسترسی public بیمعناست. سازندههای Enum ها به صورت ضمنی private هستند.
نکته دیگر اینکه در انتهای ثابت آخر یک ; گذاشتیم چون اگر در یک Enum عناصر دیگری غیر از ثابتها وجود داشته باشند گذاشتن این سِمیکالن در انتهای آخرین ثابت الزامی است.
برای فراخوانی متدهایی که در یک Enum تعریف کردهایم به صورت زیر عمل میکنیم:
Vehicle.PLANE.getCode();
شاید این سوال پیش بیاید که چرا باید برای مقادیر یک Enum متغیری مثل متغیر code تعریف کنیم؟ پاسخ این است که ثابتهای موجود در یک Enum فقط نام دارند و البته در بسیاری از مواقع وجود نام کافیست چون میتوانیم در کدهای خود همین مقادیر اسمی را با هم مقایسه کنیم مثل همان کاری که در مثالهای قبلی انجام دادیم.
اما به عنوان مثال اگر بخواهیم یکی از ثابتهای یک Enum را به یک سرور ارسال کنیم دیگر نمیتوان مثلا Vehicle.PLANE را (که همانطور که گفتیم PLANE یک شی از نوع Vehicle است) بفرستیم بلکه باید هر کدام از این اشیا حاوی مقادیری مثل عدد یا رشته باشند که بتوان از آنها استفاده کرد.
بسیار عالی بود ، خیلی شیوا و روان توضیح می دهید . بسیار سپاسگزاریم
سلام..چرا دیگه ادامه ندادید؟
سلام. چند وقتی هست که سرم خیلی شلوغه. قسمت بعد رو تا چند روز آینده قرار میدم.
ممنون…و بیشتر ممنون میشم اگه قسمت های دیگه رو هم رو زودتر اریه بدید… بینهایت
سپاسگزارم