CodeGym /Java blog /Véletlen /Enum. Gyakorlati példák. Konstruktorok és metódusok hozzá...
John Squirrels
Szint
San Francisco

Enum. Gyakorlati példák. Konstruktorok és metódusok hozzáadása

Megjelent a csoportban
Szia! Ma a Java egyik speciális adattípusáról fogunk beszélni: Enum(a "felsorolás" rövidítése). Mitől különleges? Képzeljük el, mi kell ahhoz, hogy "hónapokat" megvalósítsunk egy programban. Enum.  Gyakorlati példák.  Konstruktorok és metódusok hozzáadása - 1 Nem tűnik problémásnak, igaz? Csak azt kell meghatároznunk, hogy melyik hónap milyen tulajdonságokkal rendelkezik. Talán először a hónap nevére és a benne lévő napok számára van szükségünk. A megoldás meglehetősen egyszerűnek tűnik:

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 +
               '}';
   }
}
Az egész shabang! Van egy Monthosztályunk, a kötelező mezők, a getter/setterek és a toString(). Kivéve persze, ha hozzá kell adnunk equals()éshashCode()a teljes boldogság eléréséhez :) De itt van egy fogalmi problémánk. Valószínűleg emlékszel rá, hogy az OOP egyik fő előnye, hogy megkönnyíti az entitások valós világból való modellezését. Szék, autó, bolygó – mindezek a hétköznapi élet fogalmai könnyen ábrázolhatók egy programban az absztrakció segítségével. A probléma az, hogy néhány valós entitásnak szigorúan korlátozott értéktartománya van. Csak 4 évszak van egy évben. Csak 8 hang van egy oktávban. A naptár mindössze 12 hónapos. Danny Ocean of Ocean's 11-nek pedig csak 11 barátja van (bár ez nem számít :)) Ami számít, az az, hogy egy közönséges Java osztály nem képes modellezni ezeket az entitásokat és érvényesíteni természetes korlátaikat. A miénkMonthosztályban minden kötelező mező szerepel. De ha egy másik programozó használja, senki sem akadályozhatja meg abban, hogy teljesen őrült objektumokat hozzon létre:

public class Main {

   Month month1 = new Month("lolkek", 322);
   Month month2 = new Month("yahoooooooooooo", 12345);

}
Ha ez megjelenik a kódunkban, nem lesz könnyű megtalálni a tettest! Egyrészt az objektumokat létrehozó programozó rájönhet, hogy az Monthosztály azt jelenti, hogy "hónap egy évben", és nem ír ilyen hülyeségeket. Másrészt a programozó csak az osztálytervező által biztosított képességeket használja ki. Lehet-e tetszőleges neveket és napszámokat rendelni? Pontosan ezt kaptuk. Mit tegyünk akkor ebben a helyzetben? Őszintén szólva, a Java 1.5 megjelenése előtt a programozóknak kreatívkodniuk kellett :) Abban az időben ilyen struktúrákat készítettek:

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 +
               '}';
   }
}
Itt tizenkettőről háromra csökkentettük a hónapok számát, hogy rövidebb legyen a példa. Az ilyen tervek lehetővé tették a probléma megoldását. Az objektumok létrehozásának lehetősége egy privát konstruktorra korlátozódott:

private Month(String name, int daysCount) {
       this.name = name;
       this.daysCount = daysCount;
   }
Az osztályt használó programozók nem tudtak egyszerűen Monthobjektumokat létrehozni. Az osztályfejlesztő által biztosított végső statikus objektumokat kellett használniuk. Például így:

public class Main {

   public static void main(String[] args) {

       Month january = Month.JANUARY;
       System.out.println(january);
   }

}
A Java fejlesztői azonban felhívták a figyelmet a fennálló problémára. Persze nagyon jó, hogy a programozók a nyelven elérhető eszközök segítségével ki tudtak találni egy megoldást, de ez nem tűnik túl egyszerűnek! Kézenfekvő megoldásra volt szükség, még a kezdők számára is. És így Enumjelent meg a Java-ban. Alapvetően Enumegy Java osztály, amely korlátozott objektumértékeket biztosít. Így néz ki:

public enum Month {
  
   JANUARY,
   FEBRUARY,
   MARCH
}
A definícióban jeleztük, hogy ez Enumegy Java osztály, de ez tényleg igaz? Igen, és még ellenőrizni is tudjuk. Például próbálja meg az enumunkat örökölni Monthegy másik osztályt:

public abstract class AbstractMonth {
}

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

   JANUARY,
   FEBRUARY,
   MARCH
}
Miért történik ez? Amikor írunk:

public enum Month
a fordító ezt az utasítást a következő kódra alakítja:

public Class Month extends Enum
Mint már tudja, a Java nem támogatja a többszörös öröklődést. Ezért nem örökölhetünk AbstractMonth. Hogyan Enumhasználható ez az új konstrukció, ? És miben különbözik a régi, szántóföldi konstrukciótól static final? Nos, például a régi konstrukció nem engedte, hogy a saját értékkészletünket használjuk a kijelentésekben switch. Képzeljük el, hogy olyan programot szeretnénk létrehozni, amely emlékeztet minket a minden hónapban megünnepelt ünnepekre:

public class HolidayReminder {

   public void printHolidays(Month month) {

       switch (month) {

           // Error!
           case JANUARY:
       }
   }
}
Mint látható, a fordító itt hibát dob. De miután enummegjelent a Java 1.5-ben, minden sokkal egyszerűbb lett:

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);

   }

}
Konzol kimenet:

New Year's Day is January 1st!
Vegye figyelembe, hogy az Enumobjektumokhoz való hozzáférés statikus maradt, akárcsak a Java 1.5 előtt. Nem kell objektumot létrehoznunk Montha hónapok eléréséhez. Az enumokkal való munka során nagyon fontos, hogy ne felejtsük el, hogy ez Enumegy teljes értékű osztály. Ez azt jelenti, hogy szükség esetén konstruktorokat és metódusokat definiálhatunk benne. Például az előző kódrészletben egyszerűen megadtuk az értékeket: JANUÁR, FEBRUÁR, MÁRCIUS. MonthA felsorolásunkat azonban a következőképpen bővíthetjük :

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 +
               '}';
   }
}
Itt megadtuk a enum2 mezőnket (a hónap neve és a napok száma), egy konstruktort, amely ezeket a mezőket használja, a getter/settereket, a toString()metódust és 2 statikus metódust. Mint látható, ezzel nem volt probléma. Ismét Enumegy teljes értékű osztály:

import java.util.Arrays;

public class Main {

   public static void main(String[] args) {

       System.out.println(Arrays.toString(Month.getSummerMonths()));

   }

}
Konzol kimenet:

[Month{name='June', daysCount=30}, Month{name='July', daysCount=31}, Month{name='August', daysCount=31}]
Végül szeretnék ajánlani egy rendkívül hasznos Java könyvet, mégpedig Joshua Bloch "Effective Java" című könyvét . Enum.  Gyakorlati példák.  Konstruktorok és módszerek hozzáadása - 3A szerző a Java egyik megalkotója, így a nyelvi eszközök helyes és hozzáértő használatára vonatkozó tanácsaiban mindenképp megbízhat :) Tanóránkkal kapcsolatban azt javaslom, hogy fordítsanak különös figyelmet a könyv című fejezetére Enum. Jó olvasást! :)
Hozzászólások
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION