เมื่อเขียนโปรแกรม เรามักจะพบกับความจำเป็นในการจำกัดชุดของค่าที่ถูกต้องสำหรับประเภทข้อมูลบางประเภท ตัวอย่างเช่น วันในสัปดาห์สามารถมีได้ 7 ค่าที่แตกต่างกัน เดือนของปีสามารถมีได้ 12 ค่า และฤดูกาลสามารถมีได้ 4 ค่า เพื่อแก้ไขปัญหาดังกล่าว ภาษาโปรแกรมที่พิมพ์แบบคงที่จำนวนมากจะมีประเภทข้อมูลพิเศษ - การแจงนับ (
สมาชิก Enum เป็นอินสแตนซ์
องค์ประกอบ
เหมือนกัน แต่มีความหลากหลาย:
ตัวอย่างสุดท้ายแสดงให้เห็นถึงการใช้การสืบทอดใน
ประกาศการแจงนับ
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
คลาส และค่าที่เป็นไปได้ของประเภทที่แจกแจงเป็นenum
องค์ประกอบ -a
สมาชิก Enum เป็นอินสแตนซ์enum
ของคลาสที่สามารถเข้าถึงได้แบบคงที่
องค์ประกอบenum Season (WINTER, SPRING и т.д.)
เป็นอินสแตนซ์ที่เข้าถึงได้แบบคงที่ของenum
-class Season
ความพร้อมใช้งานคงที่ช่วยให้เราทำการเปรียบเทียบโดยใช้ตัวดำเนินการเปรียบเทียบ==
อ้างอิง ตัวอย่าง:
Season season = Season.SUMMER;
if (season == Season.AUTUMN) season = Season.WINTER;
ชื่อและหมายเลขลำดับขององค์ประกอบแจงนับ
ตามที่กล่าวไว้ก่อนหน้านี้enum
-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
มาจากคลาส การรับองค์ประกอบโดยการแสดงสตริงของชื่อบ่อยครั้งงานเกิดขึ้นจากการรับองค์ประกอบด้วยการแสดงสตริง เพื่อวัตถุประสงค์เหล่านี้ ในแต่ละ-class คอมไพลเลอร์จะสร้างวิธีสแตติกพิเศษโดยอัตโนมัติ: ซึ่งส่งคืนองค์ประกอบการแจงนับที่มีชื่อเท่ากับ ตัวอย่างการใช้งาน: 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
กันNullPointerException จะถูกโยนทิ้ง โดยวิธีการนี้มักจะถูกลืม ด้วยเหตุผลบางประการ หลายๆ คนเชื่อมั่นอย่างยิ่งว่าหากฟังก์ชันรับหนึ่งอาร์กิวเมนต์และภายใต้เงื่อนไขบางประการได้ส่งIllegalArgumentException จากนั้นเมื่อส่งผ่านที่นั่นIllegalArgumentExceptionก็จะถูกโยนด้วยเช่นกัน แต่นั่นอยู่นอกประเด็น มาต่อกัน การรับองค์ประกอบทั้งหมดของการแจงนับ บางครั้งคุณจำเป็นต้องได้รับรายการองค์ประกอบทั้งหมดของ -คลาส ณ รันไทม์ เพื่อวัตถุประสงค์เหล่านี้คอมไพลเลอร์จะสร้างเมธอดในแต่ละ -class ตัวอย่างการใช้งาน: null
null
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
-class คุณมีโอกาสที่จะเพิ่มวิธีการของคุณเองทั้งในenum
-class และองค์ประกอบ: 

enum
. เพิ่มเติมเกี่ยวกับเรื่องนี้ในภายหลัง การสืบทอดenum
ใน Java 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
จะเห็นได้ว่าคอมไพเลอร์สร้างคลาสขึ้นมา 1 คลาสType
และคลาส 3 nested
คลาสที่ได้มาจากType
.
ถอดรหัสคลาส enum พร้อมการสืบทอด
เพื่อยืนยันข้างต้น เรายังนำเสนอผลลัพธ์ของการถอดรหัสการแจงนับType
จากตัวอย่างด้านบน: 
การแจงนับและพหุสัณฐานแบบพาราเมตริก
ผู้อ่านอาจสงสัยว่า: " เหตุใดการแจงนับประเภทข้างต้นจึงไม่ใช้ยาชื่อสามัญ "enum
ความจริงก็คือว่าใน Java ห้ามใช้ยาชื่อสามัญ ดังนั้นตัวอย่างต่อไปนี้จะไม่คอมไพล์:
enum Type<T> {}
การศึกษาต่อ
เพื่อความเข้าใจที่ลึกซึ้งยิ่งขึ้นเกี่ยวกับวิธีการทำงานของการแจงนับใน Java ฉันขอแนะนำให้คุณทำความคุ้นเคยกับซอร์สโค้ดของคลาสjava.lang.Enum
และใช้ตัวถอดรหัส Jad เพื่อศึกษาโค้ดที่สร้างขึ้น นอกจากนี้ การศึกษาซอร์สโค้ดไลบรารี Java จำเป็นอย่างยิ่งในการทำความเข้าใจว่ากลไกต่างๆ ใน Java ทำงานกี่กลไก และมีประโยชน์ในการอ้างอิงสำหรับการออกแบบเชิงวัตถุ ลิงก์ไปยังแหล่งที่มาดั้งเดิม: http://alexander.lds.lg.ua/
GO TO FULL VERSION