CodeGym /Java blogg /Slumpmässig /Enum. Praktiska exempel. Lägga till konstruktörer och met...
John Squirrels
Nivå
San Francisco

Enum. Praktiska exempel. Lägga till konstruktörer och metoder

Publicerad i gruppen
Hej! Idag ska vi prata om en av Javas speciella datatyper: Enum(förkortning för "uppräkning"). Vad gör den speciell? Låt oss föreställa oss vad vi behöver för att implementera "månader" i ett program. Enum.  Praktiska exempel.  Lägga till konstruktörer och metoder - 1 Det verkar inte vara problematiskt, eller hur? Vi behöver bara bestämma vilka egenskaper som varje månad har. Kanske behöver vi först månadens namn och antalet dagar i den. Lösningen ser ganska enkel ut:

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 +
               '}';
   }
}
Hela shabang! Vi har en Monthklass, de obligatoriska fälten, getter/setters och toString(). Såvida vi inte behöver lägga till equals()ochhashCode()att uppnå fullständig lycka :) Men här har vi ett konceptuellt problem. Som du säkert kommer ihåg är en av de främsta fördelarna med OOP att det gör det enkelt att modellera enheter från den verkliga världen. En stol, en bil, en planet — alla dessa begrepp från det vanliga livet är lätt representerade i ett program med hjälp av abstraktion. Problemet är att vissa verkliga enheter har ett strikt begränsat värdeintervall. Det är bara 4 säsonger på ett år. Det finns bara 8 toner i en oktav. Kalendern har bara 12 månader. Och Danny Ocean of Ocean's 11 har bara 11 vänner (även om detta inte spelar någon roll :)) Vad som spelar roll är att en vanlig Java-klass inte kan modellera dessa enheter och upprätthålla deras naturliga begränsningar. VårMonthklass har alla obligatoriska fält. Men om en annan programmerare använder det kan ingen hindra honom eller henne från att skapa helt galna objekt:

public class Main {

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

}
Om detta visas i vår kod kommer det inte att vara lätt att hitta den skyldige! Å ena sidan kan programmeraren som skapar objekten inse att klassen Monthbetyder "månad på ett år" och inte skriva sådant nonsens. Å andra sidan utnyttjar programmeraren bara de förmågor som klassdesignern tillhandahållit. Är det möjligt att tilldela godtyckliga namn och antal dagar? Det är precis vad vi fick. Vad ska vi då göra i den här situationen? Ärligt talat, innan Java 1.5 släpptes, var programmerare tvungna att bli kreativa :) På den tiden skapade de strukturer som denna:

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 +
               '}';
   }
}
Här har vi minskat antalet månader från tolv till tre för att göra exemplet kortare. Sådana konstruktioner gjorde det möjligt att lösa problemet. Möjligheten att skapa objekt var begränsad till en privat konstruktör:

private Month(String name, int daysCount) {
       this.name = name;
       this.daysCount = daysCount;
   }
Programmerare som använder klassen kunde inte bara skapa Monthobjekt. De var tvungna att använda de slutliga statiska objekten från klassutvecklaren. Till exempel, så här:

public class Main {

   public static void main(String[] args) {

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

}
Men Java-utvecklare uppmärksammade det befintliga problemet. Visst är det bra att programmerare kunde komma på en lösning med hjälp av de verktyg som finns på språket, men det ser inte särskilt lätt ut! En uppenbar lösning behövdes, även för nybörjare. Och så Enumdök upp i Java. I grund och botten Enumär det en Java-klass som tillhandahåller en begränsad uppsättning objektvärden. Så här ser det ut:

public enum Month {
  
   JANUARY,
   FEBRUARY,
   MARCH
}
I definitionen angav vi att det Enumär en Java-klass, men är det verkligen sant? Ja, och vi kan till och med verifiera det. Försök till exempel att få vår Monthenum att ärva någon annan klass:

public abstract class AbstractMonth {
}

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

   JANUARY,
   FEBRUARY,
   MARCH
}
Varför händer det? När vi skriver:

public enum Month
kompilatorn konverterar denna sats till följande kod:

public Class Month extends Enum
Som du redan vet stöder Java inte multipelt arv. Därför kan vi inte ärva AbstractMonth. Hur kan denna nya konstruktion, , Enumanvändas? Och hur skiljer det sig från den gamla konstruktionen med static finalfält? Tja, som ett exempel lät den gamla konstruktionen oss inte använda vår egen uppsättning värden i switchuttalanden. Föreställ dig att vi vill skapa ett program som påminner oss om de högtider som firas varje månad:

public class HolidayReminder {

   public void printHolidays(Month month) {

       switch (month) {

           // Error!
           case JANUARY:
       }
   }
}
Som du kan se, ger kompilatorn ett fel här. Men när det väl enumdök upp i Java 1.5 blev allt mycket enklare:

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

   }

}
Konsolutgång:

New Year's Day is January 1st!
Observera att tillgången till Enumobjekt förblev statisk, precis som den var före Java 1.5. Vi behöver inte skapa ett Monthobjekt för att komma åt månaderna. När man arbetar med enums är det väldigt viktigt att inte glömma att det Enumär en fullfjädrad klass. Detta innebär att du vid behov kan definiera konstruktörer och metoder i den. Till exempel, i det föregående kodfragmentet angav vi helt enkelt värdena: JANUARI, FEBRUARI, MARS. Men vi kan utöka vår Monthuppräkning så här:

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 +
               '}';
   }
}
Här gav vi våra enum2 fält (namnet på månaden och antalet dagar), en konstruktor som använder dessa fält, getter/setters, metoden toString()och 2 statiska metoder. Som ni ser var det inga problem med detta. Återigen, Enumär verkligen en fullfjädrad klass:

import java.util.Arrays;

public class Main {

   public static void main(String[] args) {

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

   }

}
Konsolutgång:

[Month{name='June', daysCount=30}, Month{name='July', daysCount=31}, Month{name='August', daysCount=31}]
Slutligen vill jag tipsa om en extremt användbar Java-bok, nämligen "Effektiv Java" av Joshua Bloch . Enum.  Praktiska exempel.  Lägga till konstruktörer och metoder - 3Författaren är en av Javas skapare, så du kan definitivt lita på hans råd om hur du korrekt och kompetent använder språkets verktyg :) När det gäller vår lektion rekommenderar jag att du ägnar särskild uppmärksamhet åt bokens kapitel om Enum. Glad läsning! :)
Kommentarer
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION