CodeGym /בלוג Java /Random-HE /Enum. דוגמאות מעשיות. הוספת בנאים ושיטות
John Squirrels
רָמָה
San Francisco

Enum. דוגמאות מעשיות. הוספת בנאים ושיטות

פורסם בקבוצה
היי! היום נדבר על אחד מסוגי הנתונים המיוחדים של Java: Enum(קיצור של "ספירה"). מה מייחד אותו? בואו נדמיין מה אנחנו צריכים כדי ליישם "חודשים" בתוכנית. Enum.  דוגמאות מעשיות.  הוספת בנאים ושיטות - 1 לא נראה בעייתי, נכון? אנחנו רק צריכים לקבוע אילו נכסים יש לכל חודש. אולי קודם כל צריך את שם החודש ואת מספר הימים שבו. הפתרון נראה די פשוט:

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מחלקה, השדות הנדרשים, מגטר/מגדיר ו- toString(). אלא אם כן, כמובן, אנחנו צריכים להוסיף equals()ולהשיג hashCode()אושר מוחלט :) אבל כאן יש לנו בעיה מושגית. כפי שאתם בוודאי זוכרים, אחד היתרונות העיקריים של OOP הוא בכך שהוא מקל על מודלים של ישויות מהעולם האמיתי. כיסא, מכונית, כוכב לכת - כל המושגים הללו מהחיים הרגילים מיוצגים בקלות בתוכנית בעזרת הפשטה. הבעיה היא שלישויות מהעולם האמיתי יש טווח מוגבל בהחלט של ערכים. יש רק 4 עונות בשנה. יש רק 8 צלילים באוקטבה. בלוח השנה יש רק 12 חודשים. ול- Danny Ocean of Ocean's 11 יש רק 11 חברים (אם כי זה לא משנה :)) מה שכן משנה הוא שמחלקת ג'אווה רגילה אינה מסוגלת לעצב את הישויות הללו ולאכוף את המגבלות הטבעיות שלהן. בכיתה שלנו 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("January", 31);
   public static Month FEBRUARY = new Month("February", 28);
   public static Month MARCH = new Month("March", 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 הפנו את תשומת הלב לבעיה הקיימת. כמובן, זה נהדר שמתכנתים הצליחו להמציא פתרון באמצעות הכלים הזמינים בשפה, אבל זה נראה לא קל במיוחד! היה צורך בפתרון ברור, אפילו לטירונים. וכך Enumהופיע בג'אווה. בעיקרון, Enumהיא מחלקת Java המספקת קבוצה מוגבלת של ערכי אובייקט. כך זה נראה:

public enum Month {
  
   JANUARY,
   FEBRUARY,
   MARCH
}
בהגדרה, ציינו שזו Enumמחלקה של Java, אבל האם זה באמת נכון? כן, ואנחנו אפילו יכולים לאמת את זה. לדוגמה, נסה לגרום Monthל-enum שלנו לרשת מחלקה אחרת:

public abstract class AbstractMonth {
}

// Error! The extends clause cannot be used with an enum
public enum Month extends AbstractMonth {

   JANUARY,
   FEBRUARY,
   MARCH
}
למה זה קורה? כשאנחנו כותבים:

public enum Month
המהדר ממיר הצהרה זו לקוד הבא:

public Class Month extends Enum
כפי שאתה כבר יודע, Java אינה תומכת בירושה מרובה. לכן, אנחנו לא יכולים לרשת AbstractMonth. Enumכיצד ניתן להשתמש במבנה החדש הזה, ,? ובמה זה שונה מהמבנה הישן עם static finalשדות? ובכן, כדוגמה, המבנה הישן לא איפשר לנו להשתמש בקבוצת הערכים שלנו בהצהרות switch. תארו לעצמכם שאנחנו רוצים ליצור תוכנית שתזכיר לנו את החגים שנחגגים בכל חודש:

public class HolidayReminder {

   public void printHolidays(Month month) {

       switch (month) {

           // Error!
           case JANUARY:
       }
   }
}
כפי שאתה יכול לראות, המהדר זורק כאן שגיאה. אבל ברגע enumשהופיע ב-Java 1.5, הכל נעשה הרבה יותר פשוט:

public enum Month {

   JANUARY,
   FEBRUARY,
   MARCH
}

public class HolidayReminder {

   public void printHolidays(Month month) {

       switch (month) {
          
           case JANUARY:
               System.out.println("New Year's Day is January 1st!");
               break;
           case FEBRUARY:
               System.out.println("Valentine's Day is February 14th!");
               break;
           case MARCH:
               System.out.println("Saint Patrick's Day is March 17th!");
               break;
       }
   }
}


public class Main {

   public static void main(String[] args) {

       HolidayReminder reminder = new HolidayReminder();
       reminder.printHolidays(Month.JANUARY);

   }

}
פלט מסוף:

New Year's Day is January 1st!
שים לב שהגישה Enumלאובייקטים נשארה סטטית, בדיוק כפי שהייתה לפני Java 1.5. אנחנו לא צריכים ליצור Monthאובייקט כדי לגשת לחודשים. כשעובדים עם enums, חשוב מאוד לא לשכוח שמדובר Enumבכיתה מן המניין. המשמעות היא שבמידת הצורך ניתן להגדיר בו בנאים ושיטות. לדוגמה, בקטע הקוד הקודם, פשוט ציינו את הערכים: JANUARY, FEBRUARY, MARCH. עם זאת, אנו יכולים להרחיב את Monthהמספר שלנו כך:

public enum Month {

   JANUARY("January", 31),
   FEBRUARY("February", 28),
   MARCH("March", 31),
   APRIL("April", 30),
   MAY("May", 31),
   JUNE("June", 30),
   JULY("July", 31),
   AUGUST("August", 31),
   SEPTEMBER("September", 30),
   OCTOBER("October", 31),
   NOVEMBER("November", 30),
   DECEMBER("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 +
               '}';
   }
}
כאן נתנו את enum2 השדות שלנו (שם החודש ומספר הימים), קונסטרוקטור שמשתמש בשדות אלו, getter/seters, השיטה 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='June', daysCount=30}, Month{name='July', daysCount=31}, Month{name='August', daysCount=31}]
לבסוף, אני רוצה להמליץ ​​על ספר ג'אווה שימושי ביותר, כלומר "ג'אווה יעילה" מאת ג'ושוע בלוך . Enum.  דוגמאות מעשיות.  הוספת בנאים ושיטות - 3המחבר הוא אחד היוצרים של ג'אווה, אז אתה בהחלט יכול לסמוך על העצה שלו כיצד להשתמש נכון ומוכשר בכלים של השפה :) בהקשר לשיעור שלנו, אני ממליץ לך לשים לב במיוחד לפרק של הספר על Enum. קריאה שמחה! :)
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION