Typesafe enums جایگزین بهتری برای انواع برشماری سنتی جاوا است. در اینجا نحوه استفاده صحیح از typesafe enums در کد جاوا آورده شده است.
این مقاله شما را با تفاوت بین انواع شمارش شده و typeafe enum آشنا می کند. شما یاد خواهید گرفت که چگونه یک typeafe enum را اعلام کنید و از آن در یک دستور switch استفاده کنید، و خواهید دید که چگونه یک typesafe enum را با افزودن داده ها و رفتارها سفارشی کنید. ما همچنین نگاهی به java.lang.Enum
خواهیم انداخت، که کلاس پایه برای همه typesafe enums است.
آنچه در این آموزش جاوا خواهید آموخت
- چرا از typesafe enums استفاده می کنیم و از انواع نه شمارش شده
- نحوه استفاده از typesafe enums در دستورات سوئیچ
- نحوه افزودن داده ها و رفتارها به typesafe enums
- جزئیات و نمونه هایی از کلاس Enum
چرا از typesafe enums استفاده کنیم، نه انواع برشماری شده
یک نوع شمارش شده مجموعه ای از ثابت های مرتبط را به عنوان مقادیر خود مشخص می کند. به عنوان مثال میتوان به روزهای هفته، جهتهای قطبنمای استاندارد شمال/جنوب/شرق/غرب، اسکناس سکه یک ارز، و انواع رمز تحلیلگر واژگانی اشاره کرد.
انواع شمارششده بهطور سنتی بهعنوان دنبالهای از ثابتهای عدد صحیح پیادهسازی میشوند که با مجموعهای از ثابتهای جهت زیر نشان داده میشود:
static final int DIR_NORTH = 0;
static final int DIR_WEST = 1;
static final int DIR_EAST = 2;
static final int DIR_SOUTH = 3;
چندین مشکل در این رویکرد وجود دارد:
- ایمنی نوع ندارد: از آنجا که یک ثابت نوع برشماری شده فقط یک عدد صحیح است، هر عدد صحیحی را می توان در جایی که ثابت مورد نیاز است مشخص کرد. علاوه بر این، جمع، تفریق و سایر عملیات ریاضی را می توان بر روی این ثابت ها انجام داد. به عنوان مثال،
(DIR_NORTH + DIR_EAST) / DIR_SOUTH
)، که بی معنی است. - فضای نام موجود نیست: ثابت های یک نوع شمارش شده باید با نوعی (امیدوارم) شناسه منحصر به فرد (به عنوان مثال،
DIR_
) پیشوند شوند تا از برخورد با دیگری جلوگیری شود. ثابت های نوع برشمرده شده است. - کد شکننده است: از آنجایی که ثابتهای نوع برشماری شده در فایلهای کلاس کامپایل میشوند، جایی که مقادیر تحت اللفظی آنها (در مخزنهای ثابت) ذخیره میشوند، تغییر مقدار یک ثابت مستلزم آن است که این فایلهای کلاس و آن فایلهای کلاس کاربردی که به آنها بستگی دارد بازسازی شوند. در غیر این صورت، رفتار تعریف نشده در زمان اجرا رخ می دهد.
- اطلاعات کافی نیست: وقتی یک ثابت چاپ می شود، مقدار صحیح آن خروجی می شود. این خروجی چیزی در مورد اینکه مقدار عدد صحیح نشان می دهد به شما نمی گوید. حتی نوع برشماری شده ای که ثابت به آن تعلق دارد را مشخص نمی کند.
می توانید با استفاده از ثابت های java.lang.String
از مشکلات “عدم ایمنی نوع” و “اطلاعات کافی” جلوگیری کنید. برای مثال، ممکن است رشته نهایی ثابت DIR_NORTH = "NORTH"؛
را مشخص کنید. اگرچه مقدار ثابت معنیدارتر است، اما ثابتهای مبتنی بر String
همچنان از مشکلات ” فضای نام موجود نیست ” و شکنندگی رنج میبرند. همچنین، برخلاف مقایسههای عدد صحیح، نمیتوانید مقادیر رشته را با عملگرهای ==
و !=
(که فقط مراجع را مقایسه میکنند) مقایسه کنید.
برای حل این مشکلات، توسعه دهندگان یک جایگزین مبتنی بر کلاس به نام typesafe enum اختراع کردند. متأسفانه، این الگو دارای چالشهای متعددی بود. . من نمونه ای را نشان خواهم داد که مسائل را خلاصه می کند.
چالش های الگوی typesafe enum
کلاس Suit
نشان میدهد که چگونه میتوانید از الگوی typeafe enum برای معرفی یک نوع برشماری که چهار لباس کارت را توصیف میکند استفاده کنید:
public final class Suit // Should not be able to subclass Suit.
{
public static final Suit CLUBS = new Suit();
public static final Suit DIAMONDS = new Suit();
public static final Suit HEARTS = new Suit();
public static final Suit SPADES = new Suit();
private Suit() {} // Should not be able to introduce additional constants.
}
برای استفاده از این کلاس، باید یک متغیر Suit
معرفی کنید و آن را به یکی از ثابتهای Suit
اختصاص دهید:
Suit suit = Suit.DIAMONDS;
پس ممکن است بخواهید suit
را در یک عبارت switch
مانند این مورد بازجویی کنید:
switch (suit)
{
case Suit.CLUBS : System.out.println("clubs"); break;
case Suit.DIAMONDS: System.out.println("diamonds"); break;
case Suit.HEARTS : System.out.println("hearts"); break;
case Suit.SPADES : System.out.println("spades");
}
با این حال، هنگامی که کامپایلر جاوا با Suit.CLUBS
روبرو می شود، خطایی را گزارش می دهد که بیان می کند یک عبارت ثابت مورد نیاز است. ممکن است سعی کنید مشکل را به صورت زیر حل کنید:
switch (suit)
{
case CLUBS : System.out.println("clubs"); break;
case DIAMONDS: System.out.println("diamonds"); break;
case HEARTS : System.out.println("hearts"); break;
case SPADES : System.out.println("spades");
}
اما هنگامی که کامپایلر با CLUBS
روبرو می شود، خطایی را گزارش می دهد که نشان می دهد قادر به یافتن نماد نیست. و حتی اگر Suit
را در یک بسته قرار دهید، بسته را وارد کرده و این ثابت ها را به صورت ایستا وارد کنید، کامپایلر شکایت می کند که نمی تواند Suit
را به int تبدیل کند. code> هنگام مواجهه با
کت و شلوار
در switch(suit)
. در مورد هر case
، کامپایلر همچنین گزارش میدهد که یک عبارت ثابت مورد نیاز است.
جاوا از الگوی typesafe enum با دستورات switch
پشتیبانی نمی کند. با این حال، میتوانید از ویژگی زبان typesafe enum استفاده کنید، که مزایای الگو را در حین حل مشکلات آن در بر میگیرد. این ویژگی همچنین از switch
پشتیبانی می کند.
نحوه استفاده از typesafe enums در دستورات سوئیچ
یک اعلان enum ساده Typeafe در کد جاوا شبیه همتایان خود در زبانهای C، C++ و C# است:
enum Direction { NORTH, WEST, EAST, SOUTH }
این اعلان از کلمه کلیدی enum
برای معرفی Direction
به عنوان typeafe enum (نوع ویژه ای از کلاس) استفاده می کند، که در آن می توان روش های دلخواه را اضافه کرد و رابط های دلخواه را می توان اضافه کرد. اجرا شد. ثابتهای NORTH
، WEST
، EAST
و SOUTH
enum بهعنوان ثابت پیادهسازی میشوند. - بدنههای کلاس خاص که کلاسهای ناشناس را تعریف میکنند و کلاس Direction
را گسترش میدهند.
Direction
و سایر enumهای typeafe Enum
را گسترش میدهند و متدهای مختلفی از جمله values()
، < را به ارث میبرند. code>toString() و compareTo()
، از این کلاس. Enum
را بعداً در این مقاله بررسی خواهیم کرد.
فهرست ۱ enum فوق الذکر را اعلام می کند و از آن در عبارت switch
استفاده می کند. همچنین نحوه مقایسه دو ثابت enum را نشان می دهد تا مشخص شود کدام ثابت قبل از ثابت دیگر قرار می گیرد.
public class TEDemo
{
enum Direction { NORTH, WEST, EAST, SOUTH }
public static void main(String[] args)
{
for (int i = 0; i < Direction.values().length; i++)
{
Direction d = Direction.values()[i];
System.out.println(d);
switch (d)
{
case NORTH: System.out.println("Move north"); break;
case WEST : System.out.println("Move west"); break;
case EAST : System.out.println("Move east"); break;
case SOUTH: System.out.println("Move south"); break;
default : assert false: "unknown direction";
}
}
System.out.println(Direction.NORTH.compareTo(Direction.SOUTH));
}
}
فهرست ۱ Direction
typeafe enum را اعلام می کند و روی اعضای ثابت آن تکرار می شود که values()
برمی گرداند. برای هر مقدار، عبارت switch
(برای پشتیبانی از typeafe enums بهبود یافته است) case
را که مطابق با مقدار d
است انتخاب میکند و یک پیام مناسب را خروجی میکند. . (شما یک پیشوند ثابت enum، به عنوان مثال NORTH
را با نوع enum آن اضافه نمی کنید.) در نهایت، فهرست ۱ Direction.NORTH.compareTo(Direction.SOUTH)
را به ارزیابی می کند. تعیین کنید که آیا NORTH
قبل از SOUTH
آمده است یا خیر.
کد منبع را به صورت زیر کامپایل کنید:
javac TEDemo.java
برنامه کامپایل شده را به صورت زیر اجرا کنید:
java TEDemo
شما باید خروجی زیر را مشاهده کنید:
NORTH
Move north
WEST
Move west
EAST
Move east
SOUTH
Move south
-۳
خروجی نشان میدهد که روش ارثی toString()
نام ثابت enum را برمیگرداند و NORTH
قبل از SOUTH
در یک میآید. مقایسه این ثابت های enum.
نحوه اضافه کردن داده ها و رفتارها در typesafe enums
می توانید داده ها (به شکل فیلدها) و رفتارها (به شکل متدها) را به یک typeafe enum اضافه کنید. برای مثال، فرض کنید باید یک عدد برای سکههای کانادایی معرفی کنید، و میخواهید کلاس ابزاری برای برگرداندن تعداد نیکل، سکه، ربع یا دلار موجود در تعداد دلخواه پنی فراهم کند. فهرست ۲ نحوه انجام این کار را به شما نشان می دهد.
enum Coin
{
NICKEL(5), // constants must appear first
DIME(10),
QUARTER(25),
DOLLAR(100); // the semicolon is required
private final int valueInPennies;
Coin(int valueInPennies)
{
this.valueInPennies = valueInPennies;
}
int toCoins(int pennies)
{
return pennies / valueInPennies;
}
}
public class TEDemo
{
public static void main(String[] args)
{
if (args.length != 1)
{
System.err.println("usage: java TEDemo amountInPennies");
return;
}
int pennies = Integer.parseInt(args[0]);
for (int i = 0; i < Coin.values().length; i++)
System.out.println(pennies + " pennies contains " +
Coin.values()[i].toCoins(pennies) + " " +
Coin.values()[i].toString().toLowerCase() + "s");
}
}
فهرست ۲ ابتدا یک Coin
را اعلام می کند. فهرستی از ثابت های پارامتر شده چهار نوع سکه را مشخص می کند. آرگومان ارسال شده به هر ثابت نشان دهنده تعداد پنی هایی است که سکه نشان می دهد.
آگومان ارسال شده به هر ثابت به سازنده Coin(int valueInPennies)
ارسال می شود، که آرگومان را در قسمت نمونه valuesInPennies
ذخیره می کند. این متغیر از طریق روش نمونه toCoins()
قابل دسترسی است. به تعداد سکههای ارسال شده به پارامتر pennies
toCoin()
تقسیم میشود، و این روش نتیجه را برمیگرداند که اتفاقاً تعداد سکههای موجود در نام پولی است. توسط ثابت Coin
توصیف شده است.
در این مرحله، متوجه شدهاید که میتوانید فیلدهای نمونه، سازندهها و متدهای نمونه را در یک typeafe enum اعلام کنید. به هر حال، typesafe enum اساساً نوع خاصی از کلاس جاوا است.
روش main()
کلاس TEDemo
ابتدا تأیید میکند که یک آرگومان خط فرمان منفرد مشخص شده است. این آرگومان با فراخوانی متد parseInt()
کلاس java.lang.Integer
به یک عدد صحیح تبدیل می شود، که مقدار آرگومان رشته ای خود را به یک عدد صحیح تجزیه می کند (یا یک عدد می اندازد. استثنا زمانی که ورودی نامعتبر شناسایی شود).
حرکت به جلو، main()
روی ثابتهای Coin
تکرار میشود. از آنجایی که این ثابت ها در یک آرایه Coin[]
ذخیره می شوند، main()
Coin.values().length
را ارزیابی می کند تا طول آن را تعیین کند. آرایه. برای هر تکرار از فهرست حلقه i
، main()
Coin.values()[i]
را ارزیابی می کند تا به Coin
ثابت. هر یک از toCoins()
و toString()
را روی این ثابت فراخوانی می کند، که بیشتر ثابت می کند که Coin
نوع خاصی از کلاس است. p>
کد منبع را به صورت زیر کامپایل کنید:
javac TEDemo.java
برنامه کامپایل شده را به صورت زیر اجرا کنید:
java TEDemo
۱۹۸
شما باید خروجی زیر را مشاهده کنید:
۱۹۸ pennies contains 39 nickels
۱۹۸ pennies contains 19 dimes
۱۹۸ pennies contains 7 quarters
۱۹۸ pennies contains 1 dollars
آنچه باید در مورد Enum بدانید (Enum>)< /h2>
کامپایلر جاوا enum
را قند نحوی در نظر می گیرد. پس از مواجهه با اعلان enum typeafe، کلاسی تولید می کند که نام آن توسط اعلان مشخص شده است. این کلاس، کلاس انتزاعی Enum>
را که به عنوان کلاس پایه برای همه typesafe enum ها عمل می کند، قرار می دهد.
فهرست پارامترهای نوع رسمی
Enum
وحشتناک به نظر می رسد، اما درک آن چندان سخت نیست. برای مثال، در زمینه Coin extensions Enum
، شما می توانید این لیست پارامتر نوع رسمی را به صورت زیر تفسیر کنید:
- هر زیر کلاس
Enum
باید یک آرگومان نوع واقعی را برای Enum
ارائه دهد. برای مثال، سربرگ Coin
Enum
را مشخص میکند.
- آگومان نوع واقعی باید زیر کلاس
Enum
باشد. به عنوان مثال، Coin
یک زیر کلاس از Enum
است.
- یک زیر کلاس از
Enum
(مانند Coin
) باید از اصطلاحی پیروی کند که نام خود (Coin
) را به عنوان یک نوع واقعی ارائه میکند. استدلال.
مستندات جاوا Enum
را بررسی کنید و متوجه خواهید شد که java.lang.Object
clone()
را لغو می کند، < کد>برابر ()، finalize()
، hashCode()
و toString()
متدهای است. به جز toString()
، همه این متدهای نادیده گرفته شده نهایی
اعلام می شوند تا در یک زیر کلاس قابل بازنویسی نباشند:
clone()
برای جلوگیری از شبیهسازی ثابتها لغو میشود تا هرگز بیش از یک کپی از یک ثابت وجود نداشته باشد. در غیر این صورت، ثابت ها را نمی توان از طریق ==
و !=
مقایسه کرد.
equals()
برای مقایسه ثابت ها از طریق مراجع آنها لغو می شود. ثابتهای با هویتهای یکسان (==
) باید محتویات یکسانی داشته باشند (equals()
)، و هویتهای مختلف حاکی از محتوای متفاوت است.
finalize()
لغو می شود تا اطمینان حاصل شود که ثابت ها نمی توانند نهایی شوند.
hashCode()
لغو شده است زیرا equals()
لغو شده است.
toString()
برای برگرداندن نام ثابت لغو می شود.
Enum
نیز روش های خاص خود را ارائه می دهد. این روشها عبارتند از نهایی
compareTo()
(Enum
رابط java.lang.Comparable
را پیادهسازی میکند) روشهای getDeclaringClass()
، name()
و ordinal()
:
compareTo()
ثابت فعلی را با ثابت ارسال شده به عنوان آرگومان مقایسه میکند تا ببیند کدام ثابت قبل از ثابت دیگر در enum قرار دارد و مقداری را نشان میدهد که ترتیب آنها را نشان میدهد. این روش مرتب سازی آرایه ای از ثابت های مرتب نشده را امکان پذیر می کند.
getDeclaringClass()
شی java.lang.Class
مربوط به عدد ثابت فعلی را برمی گرداند. برای مثال، شی Class
برای Coin
، در enum Coin { PENNY،
NICKEL، DIME، QUARTER}
، هنگام فراخوانی Coin.PENNY.getDeclaringClass()
برگردانده می شود.
name()
نام ثابت را برمیگرداند. toString()
نام ثابت را نیز برمی گرداند، مگر اینکه برای برگرداندن چیزی توصیفی تر، لغو شود.
ordinal()
یک ordinal مبتنی بر صفر را برمیگرداند، یک عدد صحیح که موقعیت ثابت را در typeafe enum مشخص میکند. این عدد صحیح توسط compareTo()
استفاده می شود. برای مثال، در عبارت قبلی Direction.NORTH.compareTo(Direction.SOUTH)
، compareTo()
-۳ را برگرداند زیرا NORTH
دارای ۰ ترتیبی است. ، SOUTH
دارای ترتیبی ۳ است و ۰ – ۳ (که در این زمینه compareTo()
آن را ارزیابی می کند) برابر با -۳ است.
Enum
همچنین استاتیک عمومی > T valueOf(Class را نیز فراهم می کند
روش enumType, String name)
برای برگرداندن ثابت از typesafe enum مشخص شده با نام مشخص شده:
enumType
شی Class
enum را مشخص می کند که از آن یک ثابت را برمی گرداند.
name
نام ثابت مورد بازگشت را مشخص می کند.
به عنوان مثال، Coin penny = Enum.valueOf(Coin.class, "PENNY");
ثابت Coin
را که نام آن PENNY
به پنی
.
در نهایت، مستندات جاوا Enum
شامل روش values()
نمی شود زیرا کامپایلر این روش را در حین تولید فایل کلاس typesafe enum تولید می کند.
>
نتیجه گیری
شما باید عادت داشته باشید که به جای انواع شمارش شده سنتی از typesaf enum استفاده کنید. همچنین ایده خوبی است که از لامبدا به جای کلاس های داخلی ناشناس استفاده کنید.
کامپایلر جاوا enum
را قند نحوی در نظر می گیرد. پس از مواجهه با اعلان enum typeafe، کلاسی تولید می کند که نام آن توسط اعلان مشخص شده است. این کلاس، کلاس انتزاعی Enum
را که به عنوان کلاس پایه برای همه typesafe enum ها عمل می کند، قرار می دهد.
فهرست پارامترهای نوع رسمی
Enum
وحشتناک به نظر می رسد، اما درک آن چندان سخت نیست. برای مثال، در زمینه Coin extensions Enum
، شما می توانید این لیست پارامتر نوع رسمی را به صورت زیر تفسیر کنید:
- هر زیر کلاس
Enum
باید یک آرگومان نوع واقعی را برایEnum
ارائه دهد. برای مثال، سربرگCoin
Enum
را مشخص میکند. - آگومان نوع واقعی باید زیر کلاس
Enum
باشد. به عنوان مثال،Coin
یک زیر کلاس ازEnum
است. - یک زیر کلاس از
Enum
(مانندCoin
) باید از اصطلاحی پیروی کند که نام خود (Coin
) را به عنوان یک نوع واقعی ارائه میکند. استدلال.
مستندات جاوا Enum
را بررسی کنید و متوجه خواهید شد که java.lang.Object
clone()
را لغو می کند، < کد>برابر ()، finalize()
، hashCode()
و toString()
متدهای است. به جز toString()
، همه این متدهای نادیده گرفته شده نهایی
اعلام می شوند تا در یک زیر کلاس قابل بازنویسی نباشند:
clone()
برای جلوگیری از شبیهسازی ثابتها لغو میشود تا هرگز بیش از یک کپی از یک ثابت وجود نداشته باشد. در غیر این صورت، ثابت ها را نمی توان از طریق==
و!=
مقایسه کرد.equals()
برای مقایسه ثابت ها از طریق مراجع آنها لغو می شود. ثابتهای با هویتهای یکسان (==
) باید محتویات یکسانی داشته باشند (equals()
)، و هویتهای مختلف حاکی از محتوای متفاوت است.finalize()
لغو می شود تا اطمینان حاصل شود که ثابت ها نمی توانند نهایی شوند.hashCode()
لغو شده است زیراequals()
لغو شده است.toString()
برای برگرداندن نام ثابت لغو می شود.
Enum
نیز روش های خاص خود را ارائه می دهد. این روشها عبارتند از نهایی
compareTo()
(Enum
رابط java.lang.Comparable
را پیادهسازی میکند) روشهای getDeclaringClass()
، name()
و ordinal()
:
compareTo()
ثابت فعلی را با ثابت ارسال شده به عنوان آرگومان مقایسه میکند تا ببیند کدام ثابت قبل از ثابت دیگر در enum قرار دارد و مقداری را نشان میدهد که ترتیب آنها را نشان میدهد. این روش مرتب سازی آرایه ای از ثابت های مرتب نشده را امکان پذیر می کند.getDeclaringClass()
شیjava.lang.Class
مربوط به عدد ثابت فعلی را برمی گرداند. برای مثال، شیClass
برایCoin
، درenum Coin { PENNY،
، هنگام فراخوانی
NICKEL، DIME، QUARTER}Coin.PENNY.getDeclaringClass()
برگردانده می شود.name()
نام ثابت را برمیگرداند.toString()
نام ثابت را نیز برمی گرداند، مگر اینکه برای برگرداندن چیزی توصیفی تر، لغو شود.ordinal()
یک ordinal مبتنی بر صفر را برمیگرداند، یک عدد صحیح که موقعیت ثابت را در typeafe enum مشخص میکند. این عدد صحیح توسطcompareTo()
استفاده می شود. برای مثال، در عبارت قبلیDirection.NORTH.compareTo(Direction.SOUTH)
،compareTo()
-۳ را برگرداند زیراNORTH
دارای ۰ ترتیبی است. ،SOUTH
دارای ترتیبی ۳ است و ۰ – ۳ (که در این زمینهcompareTo()
آن را ارزیابی می کند) برابر با -۳ است.
Enum
همچنین استاتیک عمومی
برای برگرداندن ثابت از typesafe enum مشخص شده با نام مشخص شده:
روش enumType, String name)
enumType
شیClass
enum را مشخص می کند که از آن یک ثابت را برمی گرداند.name
نام ثابت مورد بازگشت را مشخص می کند.
به عنوان مثال، Coin penny = Enum.valueOf(Coin.class, "PENNY");
ثابت Coin
را که نام آن PENNY
به پنی
.
در نهایت، مستندات جاوا Enum
شامل روش values()
نمی شود زیرا کامپایلر این روش را در حین تولید فایل کلاس typesafe enum تولید می کند.
>
نتیجه گیری
شما باید عادت داشته باشید که به جای انواع شمارش شده سنتی از typesaf enum استفاده کنید. همچنین ایده خوبی است که از لامبدا به جای کلاس های داخلی ناشناس استفاده کنید.
پست های مرتبط
نحوه استفاده از typesafe enums در جاوا
نحوه استفاده از typesafe enums در جاوا
نحوه استفاده از typesafe enums در جاوا