สวัสดี! วันนี้เราจะพูดถึงประเภทข้อมูลพิเศษใน Java -
ดูเหมือนว่าปัญหาคืออะไร? คุณเพียงแค่ต้องพิจารณาว่าเดือนใดมีคุณสมบัติใดบ้าง บางทีเราอาจจำเป็นต้องทราบชื่อเดือนและจำนวนวันในเดือนนั้นก่อน วิธีแก้ปัญหาดูค่อนข้างง่าย:
ผู้เขียนเป็นหนึ่งในผู้สร้าง Java ดังนั้นคุณสามารถไว้วางใจคำแนะนำของเขาเกี่ยวกับการใช้เครื่องมือภาษาที่ถูกต้องและมีความสามารถอย่างแน่นอน :) เกี่ยวกับการบรรยายของเรา ฉันขอแนะนำให้คุณให้ความสนใจเป็นพิเศษกับบทของหนังสือที่อุทิศให้กับ
Enum
(ย่อมาจาก enumeration) คุณสมบัติของพวกเขาคืออะไร? ลองจินตนาการว่าเราต้องใช้เวลาหลายเดือนในโปรแกรม public class Month {
private String name;
private int daysCount;
public Month(String name, int daysCount) {
this.name = name;
this.daysCount = daysCount;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getDaysCount() {
return daysCount;
}
public void setDaysCount(int daysCount) {
this.daysCount = daysCount;
}
@Override
public String toString() {
return "Month{" +
"name='" + name + '\'' +
", daysCount=" + daysCount +
'}';
}
}
ขอครบชุด! เรามีคลาสMonth
, ฟิลด์ที่จำเป็น, getters-setters, toString()
. เว้นแต่equals()
จะhashCode()
ต้องเติมให้มีความสุขเต็มที่ :) อย่างไรก็ตาม เรามีปัญหาทางความคิดอยู่ ดังที่คุณอาจจำได้ ข้อดีหลักประการหนึ่งของ OOP คือทำให้การสร้างแบบจำลองเอนทิตีในโลกแห่งความเป็นจริงเป็นเรื่องง่าย เก้าอี้ รถยนต์ ดาวเคราะห์ แนวคิดทั้งหมดนี้จากชีวิตประจำวันสามารถนำเสนอในโปรแกรมโดยใช้นามธรรมได้อย่างง่ายดาย ปัญหาคือบางเอนทิตีในโลกแห่งความเป็นจริงมีความหมายที่จำกัดอย่างเคร่งครัด ในหนึ่งปีมีเพียง 4 ฤดูเท่านั้น โน้ตดนตรีมีเพียง 7 ตัวเท่านั้น ในปฏิทินมีเพียง 12 เดือนเท่านั้น Ocean มีเพื่อนเพียง 11 คนเท่านั้น (แม้ว่าจะเป็นเรื่องที่ถกเถียงกันอยู่ก็ตาม :)) กล่าวอีกนัยหนึ่ง คลาส Java ปกติไม่สามารถจำลองเอนทิตีเหล่านี้และเคารพข้อจำกัดตามธรรมชาติของพวกมันได้ ชั้นเรียนของเราMonth
มีสาขาที่จำเป็นทั้งหมด แต่ถ้าโปรแกรมเมอร์คนอื่นใช้มัน จะไม่มีใครหยุดเขาจากการสร้างวัตถุที่บ้าคลั่งโดยสิ้นเชิง:
public class Main {
Month month1 = new Month("lolkek", 322);
Month month2 = new Month("yahoooooooooooo", 12345);
}
หากปรากฏอยู่ในโปรแกรมคงหาตัวคนร้ายได้ไม่ง่ายแน่! ในแง่หนึ่ง โปรแกรมเมอร์ที่สร้างวัตถุอาจเข้าใจว่าชั้นเรียนMonth
หมายถึง "เดือนของปี" และไม่ได้เขียนเรื่องไร้สาระเช่นนั้น ในทางกลับกัน เขาแค่ใช้ประโยชน์จากโอกาสที่นักออกแบบชั้นเรียนมอบให้เขา ฉันสามารถกำหนดชื่อและจำนวนวันได้หรือไม่? พระองค์ทรงแต่งตั้งไว้ จะทำอย่างไรในสถานการณ์เช่นนี้? ก่อนการเปิดตัวภาษา Java เวอร์ชัน 1.5 โปรแกรมเมอร์ต้องพูดอย่างตรงไปตรงมาออกไป :) ในสมัยนั้นพวกเขาสร้างโครงสร้างต่อไปนี้:
public class Month {
private String name;
private int daysCount;
private Month(String name, int daysCount) {
this.name = name;
this.daysCount = daysCount;
}
public static Month JANUARY = new Month("Январь", 31);
public static Month FEBRUARY = new Month("Февраль", 28);
public static Month MARCH = new Month("Март", 31);
@Override
public String toString() {
return "Month{" +
"name='" + name + '\'' +
", daysCount=" + daysCount +
'}';
}
}
ที่นี่เราได้ลดความซับซ้อนของจำนวนเดือนลงเป็นสามเดือนแทนที่จะเป็นสิบสองเพื่อให้ตัวอย่างสั้นลง การออกแบบดังกล่าวทำให้สามารถแก้ไขปัญหาได้ ตัวเลือกสำหรับวัตถุที่สร้างขึ้นถูกจำกัดโดยตัวสร้างส่วนตัว:
private Month(String name, int daysCount) {
this.name = name;
this.daysCount = daysCount;
}
โปรแกรมเมอร์ที่ใช้คลาสไม่สามารถสร้างไฟล์Month
. พวกเขาถูกบังคับให้ใช้อ็อบเจ็กต์คงที่สุดท้ายที่ได้รับจากผู้พัฒนาคลาส มันดูเหมือนสิ่งนี้:
public class Main {
public static void main(String[] args) {
Month january = Month.JANUARY;
System.out.println(january);
}
}
อย่างไรก็ตาม นักพัฒนา Java สังเกตเห็นปัญหาที่มีอยู่แล้ว แน่นอนว่าเป็นเรื่องดีที่โปรแกรมเมอร์สามารถคิดวิธีแก้ปัญหาโดยใช้เครื่องมือที่มีในภาษานั้นได้ แต่มันก็ดูไม่ง่ายนัก! จำเป็นต้องมีวิธีแก้ปัญหาที่ชัดเจน สามารถเข้าถึงได้แม้กระทั่งผู้เริ่มต้น เป็นเช่นนี้ . ปรากฏใน Java Enum
. โดยพื้นฐานแล้วEnum
มันเป็นคลาส Java ที่ให้ชุดของอ็อบเจ็กต์ค่าที่จำกัด นี่คือสิ่งที่ดูเหมือน:
public enum Month {
JANUARY,
FEBRUARY,
MARCH
}
ในคำจำกัดความ เราระบุว่าEnum
นี่คือคลาส Java แต่นี่เป็นเรื่องจริงหรือไม่ ใช่ และเราสามารถตรวจสอบได้ ลองยกตัวอย่างการสืบทอดของเราenum Month
จากคลาสอื่น:
public abstract class AbstractMonth {
}
//ошибка! No extends clause allowed to enum
public enum Month extends AbstractMonth {
JANUARY,
FEBRUARY,
MARCH
}
ทำไมสิ่งนี้ถึงเกิดขึ้น? เมื่อเราเขียนโปรแกรม:
public enum Month
คอมไพเลอร์แปลงคำสั่งนี้เป็นโค้ดดังนี้:
public Class Month extends Enum
ดังที่คุณทราบแล้วว่า Java ไม่อนุญาตให้มีการสืบทอดหลายรายการ ดังนั้นAbstractMonth
เราจึงไม่สามารถสืบทอดจาก การออกแบบใหม่นี้สามารถEnum
นำไปใช้ได้อย่างไร? และแตกต่างจากแบบเดิมที่มีstatic final
ทุ่งนาอย่างไร? ตัวอย่างเช่นการออกแบบเก่าไม่อนุญาตให้เราใช้ชุดค่าของเราเองในswitch
-expressions ลองนึกภาพว่าเราต้องการสร้างโปรแกรมที่จะเตือนเราว่ามีการเฉลิมฉลองวันหยุดอะไรบ้างในเดือนนี้:
public class HolidayReminder {
public void printHolidays(Month month) {
switch (month) {
//error!
case JANUARY:
}
}
}
อย่างที่คุณเห็น คอมไพเลอร์แสดงข้อผิดพลาด แต่หลังจาก Java 1.5 ปรากฏขึ้นenum
ทุกอย่างก็ง่ายขึ้นมาก:
public enum Month {
JANUARY,
FEBRUARY,
MARCH
}
public class HolidayReminder {
public void printHolidays(Month month) {
switch (month) {
case JANUARY:
System.out.println("7 января будет Рождество!");
break;
case FEBRUARY:
System.out.println("В феврале празднуется День Защитника Отечества - 23 февраля!");
break;
case MARCH:
System.out.println("В марте отмечается Всемирный Женский День - 8 марта!");
break;
}
}
}
public class Main {
public static void main(String[] args) {
HolidayReminder reminder = new HolidayReminder();
reminder.printHolidays(Month.JANUARY);
}
}
เอาต์พุตคอนโซล:
7 января будет Рождество!
โปรดทราบ: การเข้าถึงออบเจ็กต์Enum
ยังคงเป็นแบบคงที่เหมือนก่อน Java 1.5 เราไม่จำเป็นต้องสร้างวัตถุMonth
เพื่อเข้าถึงเดือน เมื่อทำงานกับการแจงนับ สิ่งสำคัญมากคืออย่าลืมว่าEnum
นี่คือชั้นเรียนที่เต็มเปี่ยม ซึ่งหมายความว่า หากจำเป็น คุณสามารถกำหนดตัวสร้างและวิธีการในนั้นได้ ตัวอย่างเช่น ในโค้ดก่อนหน้านี้ เราเพียงแค่ระบุค่า JANUARY, FEBRUARY, MARCH อย่างไรก็ตาม เราสามารถขยายขอบเขตของเราenum Month
ได้ดังนี้:
public enum Month {
JANUARY("Январь", 31),
FEBRUARY("Февраль", 28),
MARCH("Март", 31),
APRIL("Апрель", 30),
MAY("Май", 31),
JUNE("Июнь", 30),
JULY("Июль", 31),
AUGUST("Август", 31),
SEPTEMBER("Сентябрь", 30),
OCTOBER("Октябрь", 31),
NOVEMBER("Ноябрь", 30),
DECEMBER("Декабрь", 31);
private String name;
private int daysCount;
Month(String name, int daysCount) {
this.name = name;
this.daysCount = daysCount;
}
public static Month[] getWinterMonths() {
return new Month[]{DECEMBER, JANUARY, FEBRUARY};
}
public static Month[] getSummerMonths() {
return new Month[]{JUNE, JULY, AUGUST};
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getDaysCount() {
return daysCount;
}
public void setDaysCount(int daysCount) {
this.daysCount = daysCount;
}
@Override
public String toString() {
return "Month{" +
"name='" + name + '\'' +
", daysCount=" + daysCount +
'}';
}
}
ที่นี่เราได้เพิ่ม 2 ฟิลด์ลงในของเราenum
- ชื่อของเดือนและจำนวนวัน, ตัวสร้างที่ใช้ฟิลด์เหล่านี้, getters-setters, เมธอดtoString()
รวมถึงเมธอดคงที่ 2 วิธี อย่างที่คุณเห็น ไม่มีปัญหากับสิ่งนี้ ดังที่เราได้กล่าวไว้ก่อนหน้านี้enum
นี่คือคลาสที่เต็มเปี่ยม:
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
System.out.println(Arrays.toString(Month.getSummerMonths()));
}
}
เอาต์พุตคอนโซล:
[Month{name='Июнь', daysCount=30}, Month{name='Июль', daysCount=31}, Month{name='Август', daysCount=31}]
สุดท้ายนี้ ฉันอยากจะแนะนำหนังสือเกี่ยวกับ Java ที่มีประโยชน์อย่างยิ่งเล่มหนึ่งให้คุณ นั่นคือ“ Effective Java” โดย Joshua Bloch 
enum
. มีประสิทธิผลในการอ่าน! :)
GO TO FULL VERSION